From 80b1392e279d98193552fc14b9a97ad9927595c9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 26 Mar 2026 01:59:55 +0000 Subject: [PATCH 01/80] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d8417fdeb..abf99ae57 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.github copilot-sdk-java - 0.2.1-java.0 + 0.2.2-java.0-SNAPSHOT jar GitHub Copilot SDK :: Java @@ -33,7 +33,7 @@ scm:git:https://github.com/github/copilot-sdk-java.git scm:git:https://github.com/github/copilot-sdk-java.git https://github.com/github/copilot-sdk-java - v0.2.1-java.0 + HEAD From 3c405b75a4a9f17e26f516e80042c51023d4397d Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Fri, 27 Mar 2026 14:31:12 -0400 Subject: [PATCH 02/80] On branch edburns/dd-2758695-virtual-threads Add **Shared `ScheduledExecutorService`** for timeouts ## CopilotSession.java - Added `ScheduledExecutorService` import. - New field `timeoutScheduler`: shared single-thread scheduler, daemon thread named `sendAndWait-timeout`. - Initialized in 3-arg constructor. - `sendAndWait()`: replaced per-call `Executors.newSingleThreadScheduledExecutor()` with `timeoutScheduler.schedule()`. Cleanup calls `timeoutTask.cancel(false)` instead of `scheduler.shutdown()`. - `close()`: added `timeoutScheduler.shutdownNow()` before the blocking `session.destroy` RPC call so stale timeouts cannot fire after close. ## TimeoutEdgeCaseTest.java (new) - `testTimeoutDoesNotFireAfterSessionClose`: proves close() cancels pending timeouts (future not completed by stale TimeoutException). - `testSendAndWaitReusesTimeoutThread`: proves two sendAndWait calls share one scheduler thread instead of spawning two. - Uses reflection to construct a hanging `JsonRpcClient` (blocking InputStream, sink OutputStream). Signed-off-by: Ed Burns --- .../github/copilot/sdk/CopilotSession.java | 21 +-- .../copilot/sdk/TimeoutEdgeCaseTest.java | 148 ++++++++++++++++++ 2 files changed, 160 insertions(+), 9 deletions(-) create mode 100644 src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java diff --git a/src/main/java/com/github/copilot/sdk/CopilotSession.java b/src/main/java/com/github/copilot/sdk/CopilotSession.java index 8c68e1e3e..8a1cefd38 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotSession.java +++ b/src/main/java/com/github/copilot/sdk/CopilotSession.java @@ -14,6 +14,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicReference; @@ -121,6 +122,7 @@ public final class CopilotSession implements AutoCloseable { private volatile EventErrorHandler eventErrorHandler; private volatile EventErrorPolicy eventErrorPolicy = EventErrorPolicy.PROPAGATE_AND_LOG_ERRORS; private volatile Map>> transformCallbacks; + private final ScheduledExecutorService timeoutScheduler; /** Tracks whether this session instance has been terminated via close(). */ private volatile boolean isTerminated = false; @@ -157,6 +159,11 @@ public final class CopilotSession implements AutoCloseable { this.sessionId = sessionId; this.rpc = rpc; this.workspacePath = workspacePath; + this.timeoutScheduler = Executors.newSingleThreadScheduledExecutor(r -> { + var t = new Thread(r, "sendAndWait-timeout"); + t.setDaemon(true); + return t; + }); } /** @@ -407,17 +414,11 @@ public CompletableFuture sendAndWait(MessageOptions optio return null; }); - // Set up timeout with daemon thread so it doesn't prevent JVM exit - var scheduler = Executors.newSingleThreadScheduledExecutor(r -> { - var t = new Thread(r, "sendAndWait-timeout"); - t.setDaemon(true); - return t; - }); - scheduler.schedule(() -> { + // Schedule timeout on the shared session-level scheduler + var timeoutTask = timeoutScheduler.schedule(() -> { if (!future.isDone()) { future.completeExceptionally(new TimeoutException("sendAndWait timed out after " + timeoutMs + "ms")); } - scheduler.shutdown(); }, timeoutMs, TimeUnit.MILLISECONDS); var result = new CompletableFuture(); @@ -429,7 +430,7 @@ public CompletableFuture sendAndWait(MessageOptions optio } catch (IOException e) { LOG.log(Level.SEVERE, "Error closing subscription", e); } - scheduler.shutdown(); + timeoutTask.cancel(false); if (!result.isDone()) { if (ex != null) { result.completeExceptionally(ex); @@ -1303,6 +1304,8 @@ public void close() { isTerminated = true; } + timeoutScheduler.shutdownNow(); + try { rpc.invoke("session.destroy", Map.of("sessionId", sessionId), Void.class).get(5, TimeUnit.SECONDS); } catch (Exception e) { diff --git a/src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java b/src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java new file mode 100644 index 000000000..0f37a0539 --- /dev/null +++ b/src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java @@ -0,0 +1,148 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.Socket; +import java.util.concurrent.CompletableFuture; + +import org.junit.jupiter.api.Test; + +import com.github.copilot.sdk.events.AssistantMessageEvent; +import com.github.copilot.sdk.json.MessageOptions; + +/** + * Tests for timeout edge cases in {@link CopilotSession#sendAndWait}. + *

+ * These tests prove two defects in the current per-call + * {@code ScheduledExecutorService} approach: + *

    + *
  1. A timeout fires after {@code close()}, leaking a {@code TimeoutException} + * onto the returned future.
  2. + *
  3. Each {@code sendAndWait} call spawns a new OS thread (~1 MB stack), + * instead of reusing a shared scheduler thread.
  4. + *
+ */ +public class TimeoutEdgeCaseTest { + + /** + * Creates a {@link JsonRpcClient} whose {@code invoke()} returns futures that + * never complete. The reader thread blocks forever on the input stream, and + * writes go to a no-op output stream. + */ + private JsonRpcClient createHangingRpcClient() throws Exception { + InputStream blockingInput = new InputStream() { + @Override + public int read() throws IOException { + try { + Thread.sleep(Long.MAX_VALUE); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return -1; + } + return -1; + } + }; + ByteArrayOutputStream sinkOutput = new ByteArrayOutputStream(); + + var ctor = JsonRpcClient.class.getDeclaredConstructor( + InputStream.class, java.io.OutputStream.class, Socket.class, Process.class); + ctor.setAccessible(true); + return (JsonRpcClient) ctor.newInstance(blockingInput, sinkOutput, null, null); + } + + /** + * After {@code close()}, the future returned by {@code sendAndWait} must NOT be + * completed by a stale timeout. + *

+ * Current buggy behavior: the per-call scheduler is not cancelled by + * {@code close()}, so its 2-second timeout fires during the 5-second + * {@code session.destroy} RPC wait, completing the future with + * {@code TimeoutException}. + *

+ * Expected behavior after fix: {@code close()} cancels pending timeouts before + * the blocking RPC call, so the future remains incomplete. + */ + @Test + void testTimeoutDoesNotFireAfterSessionClose() throws Exception { + JsonRpcClient rpc = createHangingRpcClient(); + try { + CopilotSession session = new CopilotSession("test-timeout-id", rpc); + + CompletableFuture result = session.sendAndWait( + new MessageOptions().setPrompt("hello"), 2000); + + assertFalse(result.isDone(), "Future should be pending before timeout fires"); + + // close() blocks up to 5s on session.destroy RPC. The 2s timeout + // fires during that window with the current per-call scheduler. + session.close(); + + assertFalse(result.isDone(), + "Future should not be completed by a timeout after session is closed. " + + "The per-call ScheduledExecutorService leaked a TimeoutException."); + } finally { + rpc.close(); + } + } + + /** + * A shared scheduler should reuse a single thread across multiple + * {@code sendAndWait} calls, rather than spawning a new OS thread per call. + *

+ * Current buggy behavior: two calls create two {@code sendAndWait-timeout} + * threads. + *

+ * Expected behavior after fix: two calls still use only one scheduler thread. + */ + @Test + void testSendAndWaitReusesTimeoutThread() throws Exception { + JsonRpcClient rpc = createHangingRpcClient(); + try { + CopilotSession session = new CopilotSession("test-thread-count-id", rpc); + + long baselineCount = countTimeoutThreads(); + + CompletableFuture result1 = session.sendAndWait( + new MessageOptions().setPrompt("hello1"), 30000); + + Thread.sleep(100); + long afterFirst = countTimeoutThreads(); + assertTrue(afterFirst >= baselineCount + 1, + "Expected at least one new sendAndWait-timeout thread after first call. " + + "Baseline: " + baselineCount + ", after: " + afterFirst); + + CompletableFuture result2 = session.sendAndWait( + new MessageOptions().setPrompt("hello2"), 30000); + + Thread.sleep(100); + long afterSecond = countTimeoutThreads(); + assertTrue(afterSecond == afterFirst, + "Shared scheduler should reuse the same thread — no new threads after second call. " + + "After first: " + afterFirst + ", after second: " + afterSecond); + + result1.cancel(true); + result2.cancel(true); + session.close(); + } finally { + rpc.close(); + } + } + + /** + * Counts the number of live threads whose name contains "sendAndWait-timeout". + */ + private long countTimeoutThreads() { + return Thread.getAllStackTraces().keySet().stream() + .filter(t -> t.getName().contains("sendAndWait-timeout")) + .filter(Thread::isAlive) + .count(); + } +} From a36d145b777971a22e6cfb25ba605de177f6351d Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Fri, 27 Mar 2026 14:35:06 -0400 Subject: [PATCH 03/80] On branch edburns/dd-2758695-virtual-threads Add **Shared `ScheduledExecutorService`** for timeouts ## CopilotSession.java - Added `ScheduledExecutorService` import. - New field `timeoutScheduler`: shared single-thread scheduler, daemon thread named `sendAndWait-timeout`. - Initialized in 3-arg constructor. - `sendAndWait()`: replaced per-call `Executors.newSingleThreadScheduledExecutor()` with `timeoutScheduler.schedule()`. Cleanup calls `timeoutTask.cancel(false)` instead of `scheduler.shutdown()`. - `close()`: added `timeoutScheduler.shutdownNow()` before the blocking `session.destroy` RPC call so stale timeouts cannot fire after close. ## TimeoutEdgeCaseTest.java (new) - `testTimeoutDoesNotFireAfterSessionClose`: proves close() cancels pending timeouts (future not completed by stale TimeoutException). - `testSendAndWaitReusesTimeoutThread`: proves two sendAndWait calls share one scheduler thread instead of spawning two. - Uses reflection to construct a hanging `JsonRpcClient` (blocking InputStream, sink OutputStream). Signed-off-by: Ed Burns --- .../copilot/sdk/TimeoutEdgeCaseTest.java | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java b/src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java index 0f37a0539..5fa6f7e09 100644 --- a/src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java +++ b/src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java @@ -52,8 +52,8 @@ public int read() throws IOException { }; ByteArrayOutputStream sinkOutput = new ByteArrayOutputStream(); - var ctor = JsonRpcClient.class.getDeclaredConstructor( - InputStream.class, java.io.OutputStream.class, Socket.class, Process.class); + var ctor = JsonRpcClient.class.getDeclaredConstructor(InputStream.class, java.io.OutputStream.class, + Socket.class, Process.class); ctor.setAccessible(true); return (JsonRpcClient) ctor.newInstance(blockingInput, sinkOutput, null, null); } @@ -76,8 +76,8 @@ void testTimeoutDoesNotFireAfterSessionClose() throws Exception { try { CopilotSession session = new CopilotSession("test-timeout-id", rpc); - CompletableFuture result = session.sendAndWait( - new MessageOptions().setPrompt("hello"), 2000); + CompletableFuture result = session + .sendAndWait(new MessageOptions().setPrompt("hello"), 2000); assertFalse(result.isDone(), "Future should be pending before timeout fires"); @@ -85,9 +85,8 @@ void testTimeoutDoesNotFireAfterSessionClose() throws Exception { // fires during that window with the current per-call scheduler. session.close(); - assertFalse(result.isDone(), - "Future should not be completed by a timeout after session is closed. " - + "The per-call ScheduledExecutorService leaked a TimeoutException."); + assertFalse(result.isDone(), "Future should not be completed by a timeout after session is closed. " + + "The per-call ScheduledExecutorService leaked a TimeoutException."); } finally { rpc.close(); } @@ -110,17 +109,17 @@ void testSendAndWaitReusesTimeoutThread() throws Exception { long baselineCount = countTimeoutThreads(); - CompletableFuture result1 = session.sendAndWait( - new MessageOptions().setPrompt("hello1"), 30000); + CompletableFuture result1 = session + .sendAndWait(new MessageOptions().setPrompt("hello1"), 30000); Thread.sleep(100); long afterFirst = countTimeoutThreads(); assertTrue(afterFirst >= baselineCount + 1, - "Expected at least one new sendAndWait-timeout thread after first call. " - + "Baseline: " + baselineCount + ", after: " + afterFirst); + "Expected at least one new sendAndWait-timeout thread after first call. " + "Baseline: " + + baselineCount + ", after: " + afterFirst); - CompletableFuture result2 = session.sendAndWait( - new MessageOptions().setPrompt("hello2"), 30000); + CompletableFuture result2 = session + .sendAndWait(new MessageOptions().setPrompt("hello2"), 30000); Thread.sleep(100); long afterSecond = countTimeoutThreads(); @@ -140,9 +139,7 @@ void testSendAndWaitReusesTimeoutThread() throws Exception { * Counts the number of live threads whose name contains "sendAndWait-timeout". */ private long countTimeoutThreads() { - return Thread.getAllStackTraces().keySet().stream() - .filter(t -> t.getName().contains("sendAndWait-timeout")) - .filter(Thread::isAlive) - .count(); + return Thread.getAllStackTraces().keySet().stream().filter(t -> t.getName().contains("sendAndWait-timeout")) + .filter(Thread::isAlive).count(); } } From 9e102bcba86fb156060a90c7ba0c0a87136953c7 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Fri, 27 Mar 2026 16:52:14 -0400 Subject: [PATCH 04/80] Fix memory leak from cancelled timeout tasks in CopilotSession Replace Executors.newSingleThreadScheduledExecutor with an explicit ScheduledThreadPoolExecutor so we can enable removeOnCancelPolicy(true). Without this, each call to sendAndWait() that completes normally cancels its timeout task, but the cancelled task remains in the scheduler's work queue, leaking memory over the lifetime of the session. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Ed Burns --- src/main/java/com/github/copilot/sdk/CopilotSession.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/github/copilot/sdk/CopilotSession.java b/src/main/java/com/github/copilot/sdk/CopilotSession.java index 8a1cefd38..b4a4b2c7c 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotSession.java +++ b/src/main/java/com/github/copilot/sdk/CopilotSession.java @@ -15,6 +15,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicReference; @@ -159,11 +160,13 @@ public final class CopilotSession implements AutoCloseable { this.sessionId = sessionId; this.rpc = rpc; this.workspacePath = workspacePath; - this.timeoutScheduler = Executors.newSingleThreadScheduledExecutor(r -> { + var executor = new ScheduledThreadPoolExecutor(1, r -> { var t = new Thread(r, "sendAndWait-timeout"); t.setDaemon(true); return t; }); + executor.setRemoveOnCancelPolicy(true); + this.timeoutScheduler = executor; } /** From a1668c75fbf51c49dc055fae99a874d150ff6062 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Fri, 27 Mar 2026 17:16:42 -0400 Subject: [PATCH 05/80] Fix scheduler memory leak and close() race condition in CopilotSession pom.xml Add mockito-core 5.17.0 as a test dependency. src/main/java/com/github/copilot/sdk/CopilotSession.java Replace Executors.newSingleThreadScheduledExecutor with explicit ScheduledThreadPoolExecutor and enable removeOnCancelPolicy(true) so cancelled timeout tasks are purged from the work queue immediately. Wrap timeoutScheduler.schedule() in a try-catch for RejectedExecutionException. On rejection (close() race), the event subscription is cleaned up and the returned future completes exceptionally instead of throwing uncaught. src/test/java/com/github/copilot/sdk/SchedulerShutdownRaceTest.java (new) TDD test that reproduces the scheduler shutdown race. Uses Mockito to stub JsonRpcClient.invoke(), then shuts down the scheduler without setting isTerminated, and asserts sendAndWait() returns a failed future rather than throwing RejectedExecutionException. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Ed Burns --- pom.xml | 6 ++ .../github/copilot/sdk/CopilotSession.java | 26 ++++++-- .../sdk/SchedulerShutdownRaceTest.java | 65 +++++++++++++++++++ 3 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 src/test/java/com/github/copilot/sdk/SchedulerShutdownRaceTest.java diff --git a/pom.xml b/pom.xml index abf99ae57..eee587375 100644 --- a/pom.xml +++ b/pom.xml @@ -86,6 +86,12 @@ 5.14.1 test + + org.mockito + mockito-core + 5.17.0 + test + diff --git a/src/main/java/com/github/copilot/sdk/CopilotSession.java b/src/main/java/com/github/copilot/sdk/CopilotSession.java index b4a4b2c7c..7760a499d 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotSession.java +++ b/src/main/java/com/github/copilot/sdk/CopilotSession.java @@ -14,7 +14,9 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -417,14 +419,26 @@ public CompletableFuture sendAndWait(MessageOptions optio return null; }); + var result = new CompletableFuture(); + // Schedule timeout on the shared session-level scheduler - var timeoutTask = timeoutScheduler.schedule(() -> { - if (!future.isDone()) { - future.completeExceptionally(new TimeoutException("sendAndWait timed out after " + timeoutMs + "ms")); + ScheduledFuture timeoutTask; + try { + timeoutTask = timeoutScheduler.schedule(() -> { + if (!future.isDone()) { + future.completeExceptionally( + new TimeoutException("sendAndWait timed out after " + timeoutMs + "ms")); + } + }, timeoutMs, TimeUnit.MILLISECONDS); + } catch (RejectedExecutionException e) { + try { + subscription.close(); + } catch (IOException closeEx) { + e.addSuppressed(closeEx); } - }, timeoutMs, TimeUnit.MILLISECONDS); - - var result = new CompletableFuture(); + result.completeExceptionally(e); + return result; + } // When inner future completes, run cleanup and propagate to result future.whenComplete((r, ex) -> { diff --git a/src/test/java/com/github/copilot/sdk/SchedulerShutdownRaceTest.java b/src/test/java/com/github/copilot/sdk/SchedulerShutdownRaceTest.java new file mode 100644 index 000000000..d40108592 --- /dev/null +++ b/src/test/java/com/github/copilot/sdk/SchedulerShutdownRaceTest.java @@ -0,0 +1,65 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.Test; + +import com.github.copilot.sdk.json.MessageOptions; + +/** + * Reproduces the race between {@code sendAndWait()} and {@code close()}. + *

+ * If {@code close()} shuts down the timeout scheduler after + * {@code ensureNotTerminated()} passes but before + * {@code timeoutScheduler.schedule()} executes, the schedule call throws + * {@link RejectedExecutionException}. Without a fix the exception propagates + * uncaught, leaking the event subscription and leaving the returned future + * incomplete. + */ +public class SchedulerShutdownRaceTest { + + @SuppressWarnings("unchecked") + @Test + void sendAndWaitShouldReturnFailedFutureWhenSchedulerIsShutDown() throws Exception { + // Build a session via reflection (package-private constructor) + var ctor = CopilotSession.class.getDeclaredConstructor( + String.class, JsonRpcClient.class, String.class); + ctor.setAccessible(true); + + // Mock JsonRpcClient so send() returns a pending future instead of NPE + var mockRpc = mock(JsonRpcClient.class); + when(mockRpc.invoke(any(), any(), any())) + .thenReturn(new CompletableFuture<>()); + + var session = ctor.newInstance("race-test", mockRpc, null); + + // Shut down the scheduler without setting isTerminated, + // simulating the race window between ensureNotTerminated() and schedule() + var schedulerField = CopilotSession.class.getDeclaredField("timeoutScheduler"); + schedulerField.setAccessible(true); + var scheduler = (ScheduledExecutorService) schedulerField.get(session); + scheduler.shutdownNow(); + + // With the fix: sendAndWait returns a future that completes exceptionally. + // Without the fix: sendAndWait throws RejectedExecutionException directly. + CompletableFuture result = session.sendAndWait( + new MessageOptions().setPrompt("test"), 5000); + + assertNotNull(result, "sendAndWait should return a future, not throw"); + var ex = assertThrows(ExecutionException.class, + () -> result.get(1, TimeUnit.SECONDS)); + assertInstanceOf(RejectedExecutionException.class, ex.getCause()); + } +} From a01f0b51144e6aeb0b511e2b1ee9b1d3be030184 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Fri, 27 Mar 2026 17:34:15 -0400 Subject: [PATCH 06/80] Honor documented contract: timeoutMs <= 0 means no timeout in sendAndWait src/main/java/com/github/copilot/sdk/CopilotSession.java Skip scheduling the timeout task when timeoutMs <= 0, matching the Javadoc contract that 0 or negative means "no timeout". Previously, timeoutMs=0 would schedule an immediate timeout, contradicting the docs. The timeout cancel in the whenComplete cleanup is now guarded for the null case. src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java (new) TDD test that asserts the documented contract: calling sendAndWait with timeoutMs=0 should not cause the future to complete with a TimeoutException. Uses Mockito to stub JsonRpcClient.invoke(). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../github/copilot/sdk/CopilotSession.java | 38 +++++++------ .../copilot/sdk/ZeroTimeoutContractTest.java | 53 +++++++++++++++++++ 2 files changed, 75 insertions(+), 16 deletions(-) create mode 100644 src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java diff --git a/src/main/java/com/github/copilot/sdk/CopilotSession.java b/src/main/java/com/github/copilot/sdk/CopilotSession.java index 7760a499d..b90877bc2 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotSession.java +++ b/src/main/java/com/github/copilot/sdk/CopilotSession.java @@ -421,33 +421,39 @@ public CompletableFuture sendAndWait(MessageOptions optio var result = new CompletableFuture(); - // Schedule timeout on the shared session-level scheduler - ScheduledFuture timeoutTask; - try { - timeoutTask = timeoutScheduler.schedule(() -> { - if (!future.isDone()) { - future.completeExceptionally( - new TimeoutException("sendAndWait timed out after " + timeoutMs + "ms")); - } - }, timeoutMs, TimeUnit.MILLISECONDS); - } catch (RejectedExecutionException e) { + // Schedule timeout on the shared session-level scheduler. + // Per Javadoc, timeoutMs <= 0 means "no timeout". + ScheduledFuture timeoutTask = null; + if (timeoutMs > 0) { try { - subscription.close(); - } catch (IOException closeEx) { - e.addSuppressed(closeEx); + timeoutTask = timeoutScheduler.schedule(() -> { + if (!future.isDone()) { + future.completeExceptionally( + new TimeoutException("sendAndWait timed out after " + timeoutMs + "ms")); + } + }, timeoutMs, TimeUnit.MILLISECONDS); + } catch (RejectedExecutionException e) { + try { + subscription.close(); + } catch (IOException closeEx) { + e.addSuppressed(closeEx); + } + result.completeExceptionally(e); + return result; } - result.completeExceptionally(e); - return result; } // When inner future completes, run cleanup and propagate to result + final ScheduledFuture taskToCancel = timeoutTask; future.whenComplete((r, ex) -> { try { subscription.close(); } catch (IOException e) { LOG.log(Level.SEVERE, "Error closing subscription", e); } - timeoutTask.cancel(false); + if (taskToCancel != null) { + taskToCancel.cancel(false); + } if (!result.isDone()) { if (ex != null) { result.completeExceptionally(ex); diff --git a/src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java b/src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java new file mode 100644 index 000000000..10e6f7edf --- /dev/null +++ b/src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java @@ -0,0 +1,53 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.junit.jupiter.api.Test; + +import com.github.copilot.sdk.events.AssistantMessageEvent; +import com.github.copilot.sdk.events.SessionIdleEvent; +import com.github.copilot.sdk.json.MessageOptions; + +/** + * Verifies the documented contract that {@code timeoutMs <= 0} means "no + * timeout" in {@link CopilotSession#sendAndWait(MessageOptions, long)}. + */ +public class ZeroTimeoutContractTest { + + @SuppressWarnings("unchecked") + @Test + void sendAndWaitWithZeroTimeoutShouldNotTimeOut() throws Exception { + // Build a session via reflection (package-private constructor) + var ctor = CopilotSession.class.getDeclaredConstructor( + String.class, JsonRpcClient.class, String.class); + ctor.setAccessible(true); + + var mockRpc = mock(JsonRpcClient.class); + when(mockRpc.invoke(any(), any(), any())) + .thenReturn(new CompletableFuture<>()); + + var session = ctor.newInstance("zero-timeout-test", mockRpc, null); + + // Per the Javadoc: timeoutMs of 0 means "no timeout". + // The future should NOT complete with TimeoutException. + CompletableFuture result = + session.sendAndWait(new MessageOptions().setPrompt("test"), 0); + + // Give the scheduler a chance to fire if it was (incorrectly) scheduled + Thread.sleep(200); + + // The future should still be pending — not timed out + assertFalse(result.isDone(), + "Future should not be done; timeoutMs=0 means no timeout per Javadoc"); + } +} From 9dc5933042a9dd40483c0c3476b0fc8cf18dd3f2 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Fri, 27 Mar 2026 17:47:23 -0400 Subject: [PATCH 07/80] Prevent CopilotSession leak on assertion failure in TimeoutEdgeCaseTest src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java Wrap CopilotSession in try-with-resources in both tests so the session and its scheduler thread are always cleaned up, even if an assertion fails before the explicit close() call. In test 1, the explicit session.close() is kept because it is the action under test; the try-with-resources provides a safety net via idempotent double-close. In test 2, the explicit session.close() is removed since it was purely cleanup. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../copilot/sdk/TimeoutEdgeCaseTest.java | 57 ++++++++++--------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java b/src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java index 5fa6f7e09..f97d1f254 100644 --- a/src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java +++ b/src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java @@ -74,19 +74,20 @@ public int read() throws IOException { void testTimeoutDoesNotFireAfterSessionClose() throws Exception { JsonRpcClient rpc = createHangingRpcClient(); try { - CopilotSession session = new CopilotSession("test-timeout-id", rpc); + try (CopilotSession session = new CopilotSession("test-timeout-id", rpc)) { - CompletableFuture result = session - .sendAndWait(new MessageOptions().setPrompt("hello"), 2000); + CompletableFuture result = session + .sendAndWait(new MessageOptions().setPrompt("hello"), 2000); - assertFalse(result.isDone(), "Future should be pending before timeout fires"); + assertFalse(result.isDone(), "Future should be pending before timeout fires"); - // close() blocks up to 5s on session.destroy RPC. The 2s timeout - // fires during that window with the current per-call scheduler. - session.close(); + // close() blocks up to 5s on session.destroy RPC. The 2s timeout + // fires during that window with the current per-call scheduler. + session.close(); - assertFalse(result.isDone(), "Future should not be completed by a timeout after session is closed. " - + "The per-call ScheduledExecutorService leaked a TimeoutException."); + assertFalse(result.isDone(), "Future should not be completed by a timeout after session is closed. " + + "The per-call ScheduledExecutorService leaked a TimeoutException."); + } } finally { rpc.close(); } @@ -105,31 +106,31 @@ void testTimeoutDoesNotFireAfterSessionClose() throws Exception { void testSendAndWaitReusesTimeoutThread() throws Exception { JsonRpcClient rpc = createHangingRpcClient(); try { - CopilotSession session = new CopilotSession("test-thread-count-id", rpc); + try (CopilotSession session = new CopilotSession("test-thread-count-id", rpc)) { - long baselineCount = countTimeoutThreads(); + long baselineCount = countTimeoutThreads(); - CompletableFuture result1 = session - .sendAndWait(new MessageOptions().setPrompt("hello1"), 30000); + CompletableFuture result1 = session + .sendAndWait(new MessageOptions().setPrompt("hello1"), 30000); - Thread.sleep(100); - long afterFirst = countTimeoutThreads(); - assertTrue(afterFirst >= baselineCount + 1, - "Expected at least one new sendAndWait-timeout thread after first call. " + "Baseline: " - + baselineCount + ", after: " + afterFirst); + Thread.sleep(100); + long afterFirst = countTimeoutThreads(); + assertTrue(afterFirst >= baselineCount + 1, + "Expected at least one new sendAndWait-timeout thread after first call. " + "Baseline: " + + baselineCount + ", after: " + afterFirst); - CompletableFuture result2 = session - .sendAndWait(new MessageOptions().setPrompt("hello2"), 30000); + CompletableFuture result2 = session + .sendAndWait(new MessageOptions().setPrompt("hello2"), 30000); - Thread.sleep(100); - long afterSecond = countTimeoutThreads(); - assertTrue(afterSecond == afterFirst, - "Shared scheduler should reuse the same thread — no new threads after second call. " - + "After first: " + afterFirst + ", after second: " + afterSecond); + Thread.sleep(100); + long afterSecond = countTimeoutThreads(); + assertTrue(afterSecond == afterFirst, + "Shared scheduler should reuse the same thread — no new threads after second call. " + + "After first: " + afterFirst + ", after second: " + afterSecond); - result1.cancel(true); - result2.cancel(true); - session.close(); + result1.cancel(true); + result2.cancel(true); + } } finally { rpc.close(); } From 075df313376abd8b77cf03176a6506828614cda9 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Fri, 27 Mar 2026 17:52:26 -0400 Subject: [PATCH 08/80] spotless --- .../com/github/copilot/sdk/CopilotSession.java | 1 - .../copilot/sdk/SchedulerShutdownRaceTest.java | 12 ++++-------- .../copilot/sdk/ZeroTimeoutContractTest.java | 16 +++++----------- 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/github/copilot/sdk/CopilotSession.java b/src/main/java/com/github/copilot/sdk/CopilotSession.java index b90877bc2..6ee5d8c4e 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotSession.java +++ b/src/main/java/com/github/copilot/sdk/CopilotSession.java @@ -13,7 +13,6 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; diff --git a/src/test/java/com/github/copilot/sdk/SchedulerShutdownRaceTest.java b/src/test/java/com/github/copilot/sdk/SchedulerShutdownRaceTest.java index d40108592..3d874d1e9 100644 --- a/src/test/java/com/github/copilot/sdk/SchedulerShutdownRaceTest.java +++ b/src/test/java/com/github/copilot/sdk/SchedulerShutdownRaceTest.java @@ -34,14 +34,12 @@ public class SchedulerShutdownRaceTest { @Test void sendAndWaitShouldReturnFailedFutureWhenSchedulerIsShutDown() throws Exception { // Build a session via reflection (package-private constructor) - var ctor = CopilotSession.class.getDeclaredConstructor( - String.class, JsonRpcClient.class, String.class); + var ctor = CopilotSession.class.getDeclaredConstructor(String.class, JsonRpcClient.class, String.class); ctor.setAccessible(true); // Mock JsonRpcClient so send() returns a pending future instead of NPE var mockRpc = mock(JsonRpcClient.class); - when(mockRpc.invoke(any(), any(), any())) - .thenReturn(new CompletableFuture<>()); + when(mockRpc.invoke(any(), any(), any())).thenReturn(new CompletableFuture<>()); var session = ctor.newInstance("race-test", mockRpc, null); @@ -54,12 +52,10 @@ void sendAndWaitShouldReturnFailedFutureWhenSchedulerIsShutDown() throws Excepti // With the fix: sendAndWait returns a future that completes exceptionally. // Without the fix: sendAndWait throws RejectedExecutionException directly. - CompletableFuture result = session.sendAndWait( - new MessageOptions().setPrompt("test"), 5000); + CompletableFuture result = session.sendAndWait(new MessageOptions().setPrompt("test"), 5000); assertNotNull(result, "sendAndWait should return a future, not throw"); - var ex = assertThrows(ExecutionException.class, - () -> result.get(1, TimeUnit.SECONDS)); + var ex = assertThrows(ExecutionException.class, () -> result.get(1, TimeUnit.SECONDS)); assertInstanceOf(RejectedExecutionException.class, ex.getCause()); } } diff --git a/src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java b/src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java index 10e6f7edf..249dc780b 100644 --- a/src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java +++ b/src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java @@ -9,13 +9,10 @@ import static org.mockito.Mockito.*; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import org.junit.jupiter.api.Test; import com.github.copilot.sdk.events.AssistantMessageEvent; -import com.github.copilot.sdk.events.SessionIdleEvent; import com.github.copilot.sdk.json.MessageOptions; /** @@ -28,26 +25,23 @@ public class ZeroTimeoutContractTest { @Test void sendAndWaitWithZeroTimeoutShouldNotTimeOut() throws Exception { // Build a session via reflection (package-private constructor) - var ctor = CopilotSession.class.getDeclaredConstructor( - String.class, JsonRpcClient.class, String.class); + var ctor = CopilotSession.class.getDeclaredConstructor(String.class, JsonRpcClient.class, String.class); ctor.setAccessible(true); var mockRpc = mock(JsonRpcClient.class); - when(mockRpc.invoke(any(), any(), any())) - .thenReturn(new CompletableFuture<>()); + when(mockRpc.invoke(any(), any(), any())).thenReturn(new CompletableFuture<>()); var session = ctor.newInstance("zero-timeout-test", mockRpc, null); // Per the Javadoc: timeoutMs of 0 means "no timeout". // The future should NOT complete with TimeoutException. - CompletableFuture result = - session.sendAndWait(new MessageOptions().setPrompt("test"), 0); + CompletableFuture result = session.sendAndWait(new MessageOptions().setPrompt("test"), + 0); // Give the scheduler a chance to fire if it was (incorrectly) scheduled Thread.sleep(200); // The future should still be pending — not timed out - assertFalse(result.isDone(), - "Future should not be done; timeoutMs=0 means no timeout per Javadoc"); + assertFalse(result.isDone(), "Future should not be done; timeoutMs=0 means no timeout per Javadoc"); } } From 446fe7422aa20345a7506dfddf9e204727aac467 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Mon, 30 Mar 2026 16:33:10 -0400 Subject: [PATCH 09/80] Update src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../copilot/sdk/ZeroTimeoutContractTest.java | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java b/src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java index 249dc780b..3c79ac263 100644 --- a/src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java +++ b/src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java @@ -29,19 +29,29 @@ void sendAndWaitWithZeroTimeoutShouldNotTimeOut() throws Exception { ctor.setAccessible(true); var mockRpc = mock(JsonRpcClient.class); - when(mockRpc.invoke(any(), any(), any())).thenReturn(new CompletableFuture<>()); - - var session = ctor.newInstance("zero-timeout-test", mockRpc, null); - - // Per the Javadoc: timeoutMs of 0 means "no timeout". - // The future should NOT complete with TimeoutException. - CompletableFuture result = session.sendAndWait(new MessageOptions().setPrompt("test"), - 0); - - // Give the scheduler a chance to fire if it was (incorrectly) scheduled - Thread.sleep(200); - - // The future should still be pending — not timed out - assertFalse(result.isDone(), "Future should not be done; timeoutMs=0 means no timeout per Javadoc"); + when(mockRpc.invoke(any(), any(), any())).thenAnswer(invocation -> { + Object method = invocation.getArgument(0); + if ("session.destroy".equals(method)) { + // Make session.close() non-blocking by completing destroy immediately + return CompletableFuture.completedFuture(null); + } + // For other calls (e.g., message send), return an incomplete future so the + // sendAndWait result does not complete due to a mock response. + return new CompletableFuture<>(); + }); + + try (var session = ctor.newInstance("zero-timeout-test", mockRpc, null)) { + + // Per the Javadoc: timeoutMs of 0 means "no timeout". + // The future should NOT complete with TimeoutException. + CompletableFuture result = session + .sendAndWait(new MessageOptions().setPrompt("test"), 0); + + // Give the scheduler a chance to fire if it was (incorrectly) scheduled + Thread.sleep(200); + + // The future should still be pending — not timed out + assertFalse(result.isDone(), "Future should not be done; timeoutMs=0 means no timeout per Javadoc"); + } } } From a22c1ffc3b172a18083ee5eb6b2f3f5f1fac6aef Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Mon, 30 Mar 2026 16:41:07 -0400 Subject: [PATCH 10/80] increase timeout in compaction test --- src/test/java/com/github/copilot/sdk/CompactionTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/github/copilot/sdk/CompactionTest.java b/src/test/java/com/github/copilot/sdk/CompactionTest.java index 49640ac00..ae8f8b1ea 100644 --- a/src/test/java/com/github/copilot/sdk/CompactionTest.java +++ b/src/test/java/com/github/copilot/sdk/CompactionTest.java @@ -56,7 +56,7 @@ static void teardown() throws Exception { * compaction/should_trigger_compaction_with_low_threshold_and_emit_events */ @Test - @Timeout(value = 120, unit = TimeUnit.SECONDS) + @Timeout(value = 300, unit = TimeUnit.SECONDS) void testShouldTriggerCompactionWithLowThresholdAndEmitEvents() throws Exception { ctx.configureForTest("compaction", "should_trigger_compaction_with_low_threshold_and_emit_events"); @@ -96,8 +96,8 @@ void testShouldTriggerCompactionWithLowThresholdAndEmitEvents() throws Exception // Wait for compaction to complete - it may arrive slightly after sendAndWait // returns due to async event delivery from the CLI - assertTrue(compactionCompleteLatch.await(10, TimeUnit.SECONDS), - "Should have received a compaction complete event within 10 seconds"); + assertTrue(compactionCompleteLatch.await(30, TimeUnit.SECONDS), + "Should have received a compaction complete event within 30 seconds"); long compactionStartCount = events.stream().filter(e -> e instanceof SessionCompactionStartEvent).count(); long compactionCompleteCount = events.stream().filter(e -> e instanceof SessionCompactionCompleteEvent) .count(); From 4c6c2ecb5c5053ae8b93c6d2928be2f963dbdce5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:41:23 +0000 Subject: [PATCH 11/80] Update Javadoc in TimeoutEdgeCaseTest and SchedulerShutdownRaceTest to use contract/regression language Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/82d9999d-8d2f-4ccc-b0a9-0dfe932f8f78 Co-authored-by: edburns <75821+edburns@users.noreply.github.com> --- .../sdk/SchedulerShutdownRaceTest.java | 13 ++++---- .../copilot/sdk/TimeoutEdgeCaseTest.java | 32 ++++++++----------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/test/java/com/github/copilot/sdk/SchedulerShutdownRaceTest.java b/src/test/java/com/github/copilot/sdk/SchedulerShutdownRaceTest.java index 3d874d1e9..e60e4aa34 100644 --- a/src/test/java/com/github/copilot/sdk/SchedulerShutdownRaceTest.java +++ b/src/test/java/com/github/copilot/sdk/SchedulerShutdownRaceTest.java @@ -19,14 +19,16 @@ import com.github.copilot.sdk.json.MessageOptions; /** - * Reproduces the race between {@code sendAndWait()} and {@code close()}. + * Regression coverage for the race between {@code sendAndWait()} and + * {@code close()}. *

* If {@code close()} shuts down the timeout scheduler after * {@code ensureNotTerminated()} passes but before * {@code timeoutScheduler.schedule()} executes, the schedule call throws - * {@link RejectedExecutionException}. Without a fix the exception propagates - * uncaught, leaking the event subscription and leaving the returned future - * incomplete. + * {@link RejectedExecutionException}. This test asserts that + * {@code sendAndWait()} handles this race by returning a future that completes + * exceptionally (rather than propagating the exception to the caller or leaving + * the returned future incomplete). */ public class SchedulerShutdownRaceTest { @@ -50,8 +52,7 @@ void sendAndWaitShouldReturnFailedFutureWhenSchedulerIsShutDown() throws Excepti var scheduler = (ScheduledExecutorService) schedulerField.get(session); scheduler.shutdownNow(); - // With the fix: sendAndWait returns a future that completes exceptionally. - // Without the fix: sendAndWait throws RejectedExecutionException directly. + // sendAndWait must return a failed future rather than throwing directly. CompletableFuture result = session.sendAndWait(new MessageOptions().setPrompt("test"), 5000); assertNotNull(result, "sendAndWait should return a future, not throw"); diff --git a/src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java b/src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java index f97d1f254..c5ed3af81 100644 --- a/src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java +++ b/src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java @@ -19,15 +19,16 @@ import com.github.copilot.sdk.json.MessageOptions; /** - * Tests for timeout edge cases in {@link CopilotSession#sendAndWait}. + * Regression tests for timeout edge cases in + * {@link CopilotSession#sendAndWait}. *

- * These tests prove two defects in the current per-call + * These tests assert two behavioral contracts of the shared * {@code ScheduledExecutorService} approach: *

    - *
  1. A timeout fires after {@code close()}, leaking a {@code TimeoutException} - * onto the returned future.
  2. - *
  3. Each {@code sendAndWait} call spawns a new OS thread (~1 MB stack), - * instead of reusing a shared scheduler thread.
  4. + *
  5. A pending timeout must NOT fire after {@code close()} and must NOT + * complete the returned future with a {@code TimeoutException}.
  6. + *
  7. Multiple {@code sendAndWait} calls must reuse a single shared scheduler + * thread rather than spawning a new OS thread per call.
  8. *
*/ public class TimeoutEdgeCaseTest { @@ -62,13 +63,10 @@ public int read() throws IOException { * After {@code close()}, the future returned by {@code sendAndWait} must NOT be * completed by a stale timeout. *

- * Current buggy behavior: the per-call scheduler is not cancelled by - * {@code close()}, so its 2-second timeout fires during the 5-second - * {@code session.destroy} RPC wait, completing the future with - * {@code TimeoutException}. - *

- * Expected behavior after fix: {@code close()} cancels pending timeouts before - * the blocking RPC call, so the future remains incomplete. + * Contract: {@code close()} shuts down the timeout scheduler before the + * blocking {@code session.destroy} RPC call, so any pending timeout task is + * cancelled and the future remains incomplete (not exceptionally completed with + * {@code TimeoutException}). */ @Test void testTimeoutDoesNotFireAfterSessionClose() throws Exception { @@ -94,13 +92,11 @@ void testTimeoutDoesNotFireAfterSessionClose() throws Exception { } /** - * A shared scheduler should reuse a single thread across multiple + * A shared scheduler must reuse a single thread across multiple * {@code sendAndWait} calls, rather than spawning a new OS thread per call. *

- * Current buggy behavior: two calls create two {@code sendAndWait-timeout} - * threads. - *

- * Expected behavior after fix: two calls still use only one scheduler thread. + * Contract: after two consecutive {@code sendAndWait} calls the number of live + * {@code sendAndWait-timeout} threads must not increase after the second call. */ @Test void testSendAndWaitReusesTimeoutThread() throws Exception { From c67dbb3ab08a968a5f65ca1184746c807d145d0d Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Mon, 30 Mar 2026 16:48:48 -0400 Subject: [PATCH 12/80] Updates to gitignore for JTDLS related artifacts --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 8d7f42429..ddb2508ba 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ smoke-test *job-logs.txt temporary-prompts/ changebundle.txt* +.classpath +.project +.settings From 11681a9904a280da5d7987b10610723e7fe5605c Mon Sep 17 00:00:00 2001 From: brunoborges <129743+brunoborges@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:56:28 +0000 Subject: [PATCH 13/80] Update JaCoCo coverage badge --- .github/badges/jacoco.svg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/badges/jacoco.svg b/.github/badges/jacoco.svg index ddc73f3a8..19da90d2e 100644 --- a/.github/badges/jacoco.svg +++ b/.github/badges/jacoco.svg @@ -12,7 +12,7 @@ coverage coverage - 84.8% - 84.8% + 85% + 85% From 2ba6e1dc1083fd5fade553fcf515a0d17aeba349 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Tue, 31 Mar 2026 13:30:23 -0400 Subject: [PATCH 14/80] On branch edburns/spotless-agentic-workflow-42 modified: .github/copilot-instructions.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added a new "Pre-commit Hooks and Formatting (Coding Agent)" section that: - Explains the hook is automatically enabled via copilot-setup-steps.yml - Gives explicit 3-step recovery instructions: mvn spotless:apply → git add -u → retry commit - Recommends running mvn spotless:apply proactively before committing Now when the Copilot coding agent starts a session, the setup steps will enable the pre-commit hook, and if a commit is rejected by Spotless formatting checks, the agent has clear instructions to fix and retry. modified: .github/workflows/copilot-setup-steps.yml - Added a new step "Enable pre-commit hooks" that runs git config core.hooksPath .githooks before the verification step - Updated the verification step to also print the configured hooks path for confirmation Signed-off-by: Ed Burns --- .github/copilot-instructions.md | 12 ++++++++++++ .github/workflows/copilot-setup-steps.yml | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index d7dafb081..e3a8eb275 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -244,6 +244,18 @@ This SDK is designed to be **lightweight with minimal dependencies**: 5. Check for security vulnerabilities 6. Get team approval for non-trivial additions +## Pre-commit Hooks and Formatting (Coding Agent) + +The repository has a pre-commit hook (`.githooks/pre-commit`) that is **automatically enabled** in the Copilot coding agent environment via `copilot-setup-steps.yml`. The hook runs `mvn spotless:check` on any commit that includes changes under `src/`. + +**If a commit fails due to the pre-commit hook:** + +1. Run `mvn spotless:apply` to auto-fix formatting issues. +2. Re-stage the changed files with `git add -u`. +3. Retry the commit. + +**Best practice:** Always run `mvn spotless:apply` before committing Java source changes to avoid hook failures in the first place. If you forget and the hook rejects the commit, follow the three steps above and continue. + ## Commit and PR Guidelines ### Commit Messages diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 6a0cdec5b..8d8aa75c9 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -41,6 +41,10 @@ jobs: distribution: 'temurin' cache: 'maven' + # Enable pre-commit hooks so Spotless formatting is enforced on every commit + - name: Enable pre-commit hooks + run: git config core.hooksPath .githooks + # Verify installations - name: Verify tool installations run: | @@ -50,4 +54,6 @@ jobs: java -version gh --version gh aw version + echo "--- Git hooks path ---" + git config core.hooksPath echo "✅ All tools installed successfully" From dc71acbd18e0da9816c5f548c802213456e90b63 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Tue, 31 Mar 2026 13:34:32 -0400 Subject: [PATCH 15/80] Update .github/workflows/copilot-setup-steps.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/copilot-setup-steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 8d8aa75c9..145629457 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -41,7 +41,7 @@ jobs: distribution: 'temurin' cache: 'maven' - # Enable pre-commit hooks so Spotless formatting is enforced on every commit + # Enable repository pre-commit hooks (including Spotless checks for relevant source changes) - name: Enable pre-commit hooks run: git config core.hooksPath .githooks From 59b7fa116f8516fbc5a580a632c60778c2c1c7b9 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Fri, 27 Mar 2026 17:20:02 -0400 Subject: [PATCH 16/80] Add optional Executor to CopilotClientOptions; wire all internal *Async calls through it; shared timeout scheduler. src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java - Added `Executor` field, `getExecutor()`, fluent `setExecutor(Executor)` with pending-null guard, and clone support. src/main/java/com/github/copilot/sdk/CopilotClient.java - Extracted `startCoreBody()` from `startCore()` lambda; `supplyAsync` uses provided executor when non-null. - `stop()` routes session-close `runAsync` through provided executor when non-null. - Passes executor to `RpcHandlerDispatcher` constructor. - Sets executor on new sessions via `session.setExecutor()` in `createSession` and `resumeSession`. src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java - Added `Executor` field and 3-arg constructor. - All 5 `CompletableFuture.runAsync()` calls now go through private `runAsync(Runnable)` helper that uses executor when non-null. src/main/java/com/github/copilot/sdk/CopilotSession.java - Added `Executor` field and package-private `setExecutor()`. - Replaced per-call `ScheduledExecutorService` with shared `timeoutScheduler` (daemon thread, shut down in `close()`). - `executeToolAndRespondAsync` and `executePermissionAndRespondAsync` use executor when non-null. src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java (new) - 6 E2E tests using `TrackingExecutor` decorator to verify all `*Async` paths route through the provided executor: client start, tool call, permission, user input, hooks, and client stop. src/test/java/com/github/copilot/sdk/RpcHandlerDispatcherTest.java - Updated constructor call to pass `null` for new executor parameter. --- .../com/github/copilot/sdk/CopilotClient.java | 83 ++-- .../github/copilot/sdk/CopilotSession.java | 29 +- .../copilot/sdk/RpcHandlerDispatcher.java | 26 +- .../sdk/json/CopilotClientOptions.java | 34 ++ .../copilot/sdk/ExecutorWiringTest.java | 368 ++++++++++++++++++ .../copilot/sdk/RpcHandlerDispatcherTest.java | 2 +- 6 files changed, 498 insertions(+), 44 deletions(-) create mode 100644 src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java diff --git a/src/main/java/com/github/copilot/sdk/CopilotClient.java b/src/main/java/com/github/copilot/sdk/CopilotClient.java index 707469428..00dea3876 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotClient.java +++ b/src/main/java/com/github/copilot/sdk/CopilotClient.java @@ -13,6 +13,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; @@ -150,42 +151,48 @@ public CompletableFuture start() { private CompletableFuture startCore() { LOG.fine("Starting Copilot client"); - return CompletableFuture.supplyAsync(() -> { - try { - JsonRpcClient rpc; - Process process = null; - - if (optionsHost != null && optionsPort != null) { - // External server (TCP) - rpc = serverManager.connectToServer(null, optionsHost, optionsPort); - } else { - // Child process (stdio or TCP) - CliServerManager.ProcessInfo processInfo = serverManager.startCliServer(); - process = processInfo.process(); - rpc = serverManager.connectToServer(process, processInfo.port() != null ? "localhost" : null, - processInfo.port()); - } + Executor exec = options.getExecutor(); + return exec != null + ? CompletableFuture.supplyAsync(this::startCoreBody, exec) + : CompletableFuture.supplyAsync(this::startCoreBody); + } - Connection connection = new Connection(rpc, process); + private Connection startCoreBody() { + try { + JsonRpcClient rpc; + Process process = null; + + if (optionsHost != null && optionsPort != null) { + // External server (TCP) + rpc = serverManager.connectToServer(null, optionsHost, optionsPort); + } else { + // Child process (stdio or TCP) + CliServerManager.ProcessInfo processInfo = serverManager.startCliServer(); + process = processInfo.process(); + rpc = serverManager.connectToServer(process, processInfo.port() != null ? "localhost" : null, + processInfo.port()); + } - // Register handlers for server-to-client calls - RpcHandlerDispatcher dispatcher = new RpcHandlerDispatcher(sessions, lifecycleManager::dispatch); - dispatcher.registerHandlers(rpc); + Connection connection = new Connection(rpc, process); - // Verify protocol version - verifyProtocolVersion(connection); + // Register handlers for server-to-client calls + RpcHandlerDispatcher dispatcher = new RpcHandlerDispatcher(sessions, lifecycleManager::dispatch, + options.getExecutor()); + dispatcher.registerHandlers(rpc); - LOG.info("Copilot client connected"); - return connection; - } catch (Exception e) { - String stderr = serverManager.getStderrOutput(); - if (!stderr.isEmpty()) { - throw new CompletionException( - new IOException("CLI process exited unexpectedly. stderr: " + stderr, e)); - } - throw new CompletionException(e); + // Verify protocol version + verifyProtocolVersion(connection); + + LOG.info("Copilot client connected"); + return connection; + } catch (Exception e) { + String stderr = serverManager.getStderrOutput(); + if (!stderr.isEmpty()) { + throw new CompletionException( + new IOException("CLI process exited unexpectedly. stderr: " + stderr, e)); } - }); + throw new CompletionException(e); + } } private static final int MIN_PROTOCOL_VERSION = 2; @@ -228,15 +235,19 @@ private void verifyProtocolVersion(Connection connection) throws Exception { */ public CompletableFuture stop() { var closeFutures = new ArrayList>(); + Executor exec = options.getExecutor(); for (CopilotSession session : new ArrayList<>(sessions.values())) { - closeFutures.add(CompletableFuture.runAsync(() -> { + Runnable closeTask = () -> { try { session.close(); } catch (Exception e) { LOG.log(Level.WARNING, "Error closing session " + session.getSessionId(), e); } - })); + }; + closeFutures.add(exec != null + ? CompletableFuture.runAsync(closeTask, exec) + : CompletableFuture.runAsync(closeTask)); } sessions.clear(); @@ -329,6 +340,9 @@ public CompletableFuture createSession(SessionConfig config) { : java.util.UUID.randomUUID().toString(); var session = new CopilotSession(sessionId, connection.rpc); + if (options.getExecutor() != null) { + session.setExecutor(options.getExecutor()); + } SessionRequestBuilder.configureSession(session, config); sessions.put(sessionId, session); @@ -399,6 +413,9 @@ public CompletableFuture resumeSession(String sessionId, ResumeS return ensureConnected().thenCompose(connection -> { // Register the session before the RPC call to avoid missing early events. var session = new CopilotSession(sessionId, connection.rpc); + if (options.getExecutor() != null) { + session.setExecutor(options.getExecutor()); + } SessionRequestBuilder.configureSession(session, config); sessions.put(sessionId, session); diff --git a/src/main/java/com/github/copilot/sdk/CopilotSession.java b/src/main/java/com/github/copilot/sdk/CopilotSession.java index 6ee5d8c4e..485c39312 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotSession.java +++ b/src/main/java/com/github/copilot/sdk/CopilotSession.java @@ -13,6 +13,8 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; @@ -125,6 +127,7 @@ public final class CopilotSession implements AutoCloseable { private volatile EventErrorPolicy eventErrorPolicy = EventErrorPolicy.PROPAGATE_AND_LOG_ERRORS; private volatile Map>> transformCallbacks; private final ScheduledExecutorService timeoutScheduler; + private volatile Executor executor; /** Tracks whether this session instance has been terminated via close(). */ private volatile boolean isTerminated = false; @@ -170,6 +173,14 @@ public final class CopilotSession implements AutoCloseable { this.timeoutScheduler = executor; } + /** + * Sets the executor for internal async operations. Package-private; called by + * CopilotClient after construction. + */ + void setExecutor(Executor executor) { + this.executor = executor; + } + /** * Gets the unique identifier for this session. * @@ -673,7 +684,7 @@ private void handleBroadcastEventAsync(AbstractSessionEvent event) { */ private void executeToolAndRespondAsync(String requestId, String toolName, String toolCallId, Object arguments, ToolDefinition tool) { - CompletableFuture.runAsync(() -> { + Runnable task = () -> { try { JsonNode argumentsNode = arguments instanceof JsonNode jn ? jn @@ -718,7 +729,12 @@ private void executeToolAndRespondAsync(String requestId, String toolName, Strin LOG.log(Level.WARNING, "Error sending tool error for requestId=" + requestId, sendEx); } } - }); + }; + if (executor != null) { + CompletableFuture.runAsync(task, executor); + } else { + CompletableFuture.runAsync(task); + } } /** @@ -727,7 +743,7 @@ private void executeToolAndRespondAsync(String requestId, String toolName, Strin */ private void executePermissionAndRespondAsync(String requestId, PermissionRequest permissionRequest, PermissionHandler handler) { - CompletableFuture.runAsync(() -> { + Runnable task = () -> { try { var invocation = new PermissionInvocation(); invocation.setSessionId(sessionId); @@ -766,7 +782,12 @@ private void executePermissionAndRespondAsync(String requestId, PermissionReques LOG.log(Level.WARNING, "Error sending permission denied for requestId=" + requestId, sendEx); } } - }); + }; + if (executor != null) { + CompletableFuture.runAsync(task, executor); + } else { + CompletableFuture.runAsync(task); + } } /** diff --git a/src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java b/src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java index 101f68528..9f55938af 100644 --- a/src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java +++ b/src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java @@ -9,6 +9,7 @@ import java.util.Collections; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; import java.util.logging.Level; import java.util.logging.Logger; @@ -45,6 +46,7 @@ final class RpcHandlerDispatcher { private final Map sessions; private final LifecycleEventDispatcher lifecycleDispatcher; + private final Executor executor; /** * Creates a dispatcher with session registry and lifecycle dispatcher. @@ -53,10 +55,14 @@ final class RpcHandlerDispatcher { * the session registry to look up sessions by ID * @param lifecycleDispatcher * callback for dispatching lifecycle events + * @param executor + * the executor for async dispatch, or {@code null} for default */ - RpcHandlerDispatcher(Map sessions, LifecycleEventDispatcher lifecycleDispatcher) { + RpcHandlerDispatcher(Map sessions, LifecycleEventDispatcher lifecycleDispatcher, + Executor executor) { this.sessions = sessions; this.lifecycleDispatcher = lifecycleDispatcher; + this.executor = executor; } /** @@ -118,7 +124,7 @@ private void handleLifecycleEvent(JsonNode params) { } private void handleToolCall(JsonRpcClient rpc, String requestId, JsonNode params) { - CompletableFuture.runAsync(() -> { + runAsync(() -> { try { String sessionId = params.get("sessionId").asText(); String toolCallId = params.get("toolCallId").asText(); @@ -178,7 +184,7 @@ private void handleToolCall(JsonRpcClient rpc, String requestId, JsonNode params } private void handlePermissionRequest(JsonRpcClient rpc, String requestId, JsonNode params) { - CompletableFuture.runAsync(() -> { + runAsync(() -> { try { String sessionId = params.get("sessionId").asText(); JsonNode permissionRequest = params.get("permissionRequest"); @@ -222,7 +228,7 @@ private void handlePermissionRequest(JsonRpcClient rpc, String requestId, JsonNo private void handleUserInputRequest(JsonRpcClient rpc, String requestId, JsonNode params) { LOG.fine("Received userInput.request: " + params); - CompletableFuture.runAsync(() -> { + runAsync(() -> { try { String sessionId = params.get("sessionId").asText(); String question = params.get("question").asText(); @@ -278,7 +284,7 @@ private void handleUserInputRequest(JsonRpcClient rpc, String requestId, JsonNod } private void handleHooksInvoke(JsonRpcClient rpc, String requestId, JsonNode params) { - CompletableFuture.runAsync(() -> { + runAsync(() -> { try { String sessionId = params.get("sessionId").asText(); String hookType = params.get("hookType").asText(); @@ -321,7 +327,7 @@ interface LifecycleEventDispatcher { } private void handleSystemMessageTransform(JsonRpcClient rpc, String requestId, JsonNode params) { - CompletableFuture.runAsync(() -> { + runAsync(() -> { try { final long requestIdLong; try { @@ -359,4 +365,12 @@ private void handleSystemMessageTransform(JsonRpcClient rpc, String requestId, J } }); } + + private void runAsync(Runnable task) { + if (executor != null) { + CompletableFuture.runAsync(task, executor); + } else { + CompletableFuture.runAsync(task); + } + } } diff --git a/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java b/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java index 4cdee912c..33d84a9c5 100644 --- a/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java +++ b/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; import java.util.function.Supplier; import com.fasterxml.jackson.annotation.JsonInclude; @@ -49,6 +50,7 @@ public class CopilotClientOptions { private Boolean useLoggedInUser; private Supplier>> onListModels; private TelemetryConfig telemetry; + private Executor executor; /** * Gets the path to the Copilot CLI executable. @@ -412,6 +414,37 @@ public CopilotClientOptions setTelemetry(TelemetryConfig telemetry) { return this; } + /** + * Gets the executor used for internal asynchronous operations. + * + * @return the executor, or {@code null} to use the default + * {@code ForkJoinPool.commonPool()} + */ + public Executor getExecutor() { + return executor; + } + + /** + * Sets the executor used for internal asynchronous operations. + *

+ * When provided, the SDK uses this executor for all internal + * {@code CompletableFuture} combinators instead of the default + * {@code ForkJoinPool.commonPool()}. This allows callers to isolate SDK + * work onto a dedicated thread pool or integrate with container-managed + * threading. + * + * @param executor + * the executor to use, or {@code null} for the default + * @return this options instance for fluent chaining + */ + public CopilotClientOptions setExecutor(Executor executor) { + if (null == executor) { + throw new IllegalArgumentException("PENDING(copilot): not implemented"); + } + this.executor = executor; + return this; + } + /** * Creates a shallow clone of this {@code CopilotClientOptions} instance. *

@@ -439,6 +472,7 @@ public CopilotClientOptions clone() { copy.useLoggedInUser = this.useLoggedInUser; copy.onListModels = this.onListModels; copy.telemetry = this.telemetry; + copy.executor = this.executor; return copy; } } diff --git a/src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java b/src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java new file mode 100644 index 000000000..736564139 --- /dev/null +++ b/src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java @@ -0,0 +1,368 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk; + +import static org.junit.jupiter.api.Assertions.*; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import com.github.copilot.sdk.events.AssistantMessageEvent; +import com.github.copilot.sdk.json.CopilotClientOptions; +import com.github.copilot.sdk.json.MessageOptions; +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.PreToolUseHookOutput; +import com.github.copilot.sdk.json.SessionConfig; +import com.github.copilot.sdk.json.SessionHooks; +import com.github.copilot.sdk.json.ToolDefinition; +import com.github.copilot.sdk.json.UserInputResponse; + +/** + * TDD red-phase tests verifying that when an {@link Executor} is provided via + * {@link CopilotClientOptions#setExecutor(Executor)}, all internal + * {@code CompletableFuture.*Async} calls are routed through that executor + * instead of {@code ForkJoinPool.commonPool()}. + * + *

+ * Uses a {@link TrackingExecutor} decorator that delegates to a real executor + * while counting task submissions. After SDK operations complete, the tests + * assert the decorator was invoked. + *

+ */ +public class ExecutorWiringTest { + + private static E2ETestContext ctx; + + @BeforeAll + static void setup() throws Exception { + ctx = E2ETestContext.create(); + } + + @AfterAll + static void teardown() throws Exception { + if (ctx != null) { + ctx.close(); + } + } + + /** + * A decorator executor that delegates to a real executor while counting + * task submissions. + */ + static class TrackingExecutor implements Executor { + + private final Executor delegate; + private final AtomicInteger taskCount = new AtomicInteger(0); + + TrackingExecutor(Executor delegate) { + this.delegate = delegate; + } + + @Override + public void execute(Runnable command) { + taskCount.incrementAndGet(); + delegate.execute(command); + } + + int getTaskCount() { + return taskCount.get(); + } + } + + 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"); + } + return options; + } + + /** + * Verifies that client start-up routes through the provided executor. + * + *

+ * {@code CopilotClient.startCore()} uses + * {@code CompletableFuture.supplyAsync(...)} to initialize the connection. + * This test asserts that the start-up task goes through the caller-supplied + * executor, not {@code ForkJoinPool.commonPool()}. + *

+ * + * @see Snapshot: tools/invokes_custom_tool + */ + @Test + void testClientStartUsesProvidedExecutor() throws Exception { + ctx.configureForTest("tools", "invokes_custom_tool"); + + TrackingExecutor trackingExecutor = new TrackingExecutor(ForkJoinPool.commonPool()); + int beforeStart = trackingExecutor.getTaskCount(); + + try (CopilotClient client = new CopilotClient(createOptionsWithExecutor(trackingExecutor))) { + client.start().get(30, TimeUnit.SECONDS); + + assertTrue(trackingExecutor.getTaskCount() > beforeStart, + "Expected the tracking executor to have been invoked during client start, " + + "but task count did not increase. CopilotClient.startCore() is not " + + "routing supplyAsync through the provided executor."); + } + } + + /** + * Verifies that tool call dispatch routes through the provided executor. + * + *

+ * When a custom tool is invoked by the LLM, the + * {@code RpcHandlerDispatcher} calls + * {@code CompletableFuture.runAsync(...)} to dispatch the tool handler. + * This test asserts that dispatch goes through the caller-supplied executor. + *

+ * + * @see Snapshot: tools/invokes_custom_tool + */ + @Test + void testToolCallDispatchUsesProvidedExecutor() throws Exception { + ctx.configureForTest("tools", "invokes_custom_tool"); + + TrackingExecutor trackingExecutor = new TrackingExecutor(ForkJoinPool.commonPool()); + + var parameters = new HashMap(); + var properties = new HashMap(); + var inputProp = new HashMap(); + inputProp.put("type", "string"); + inputProp.put("description", "String to encrypt"); + properties.put("input", inputProp); + parameters.put("type", "object"); + parameters.put("properties", properties); + parameters.put("required", List.of("input")); + + ToolDefinition encryptTool = ToolDefinition.create("encrypt_string", "Encrypts a string", parameters, + (invocation) -> { + Map args = invocation.getArguments(); + String input = (String) args.get("input"); + return CompletableFuture.completedFuture(input.toUpperCase()); + }); + + // Reset count after client construction to isolate tool-call dispatch + try (CopilotClient client = new CopilotClient(createOptionsWithExecutor(trackingExecutor))) { + CopilotSession session = client.createSession(new SessionConfig().setTools(List.of(encryptTool)) + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get(); + + int beforeToolCall = trackingExecutor.getTaskCount(); + + AssistantMessageEvent response = session + .sendAndWait(new MessageOptions().setPrompt("Use encrypt_string to encrypt this string: Hello")) + .get(60, TimeUnit.SECONDS); + + assertNotNull(response); + + assertTrue(trackingExecutor.getTaskCount() > beforeToolCall, + "Expected the tracking executor to have been invoked for tool call dispatch, " + + "but task count did not increase after sendAndWait. " + + "RpcHandlerDispatcher is not routing runAsync through the provided executor."); + + session.close(); + } + } + + /** + * Verifies that permission request dispatch routes through the provided + * executor. + * + *

+ * When the LLM requests a permission, the {@code RpcHandlerDispatcher} + * calls {@code CompletableFuture.runAsync(...)} to dispatch the permission + * handler. This test asserts that dispatch goes through the caller-supplied + * executor. + *

+ * + * @see Snapshot: permissions/permission_handler_for_write_operations + */ + @Test + void testPermissionDispatchUsesProvidedExecutor() throws Exception { + ctx.configureForTest("permissions", "permission_handler_for_write_operations"); + + TrackingExecutor trackingExecutor = new TrackingExecutor(ForkJoinPool.commonPool()); + + var config = new SessionConfig().setOnPermissionRequest((request, invocation) -> CompletableFuture + .completedFuture(new PermissionRequestResult().setKind("approved"))); + + try (CopilotClient client = new CopilotClient(createOptionsWithExecutor(trackingExecutor))) { + CopilotSession session = client.createSession(config).get(); + + Path testFile = ctx.getWorkDir().resolve("test.txt"); + Files.writeString(testFile, "original content"); + + int beforeSend = trackingExecutor.getTaskCount(); + + session.sendAndWait( + new MessageOptions().setPrompt("Edit test.txt and replace 'original' with 'modified'")) + .get(60, TimeUnit.SECONDS); + + assertTrue(trackingExecutor.getTaskCount() > beforeSend, + "Expected the tracking executor to have been invoked for permission dispatch, " + + "but task count did not increase after sendAndWait. " + + "RpcHandlerDispatcher is not routing permission runAsync through the provided executor."); + + session.close(); + } + } + + /** + * Verifies that user input request dispatch routes through the provided + * executor. + * + *

+ * When the LLM asks for user input, the {@code RpcHandlerDispatcher} calls + * {@code CompletableFuture.runAsync(...)} to dispatch the user input + * handler. This test asserts that dispatch goes through the caller-supplied + * executor. + *

+ * + * @see Snapshot: + * ask_user/should_invoke_user_input_handler_when_model_uses_ask_user_tool + */ + @Test + void testUserInputDispatchUsesProvidedExecutor() throws Exception { + ctx.configureForTest("ask_user", "should_invoke_user_input_handler_when_model_uses_ask_user_tool"); + + TrackingExecutor trackingExecutor = new TrackingExecutor(ForkJoinPool.commonPool()); + + var config = new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setOnUserInputRequest((request, invocation) -> { + String answer = (request.getChoices() != null && !request.getChoices().isEmpty()) + ? request.getChoices().get(0) + : "freeform answer"; + boolean wasFreeform = request.getChoices() == null || request.getChoices().isEmpty(); + return CompletableFuture + .completedFuture(new UserInputResponse().setAnswer(answer).setWasFreeform(wasFreeform)); + }); + + try (CopilotClient client = new CopilotClient(createOptionsWithExecutor(trackingExecutor))) { + CopilotSession session = client.createSession(config).get(); + + int beforeSend = trackingExecutor.getTaskCount(); + + session.sendAndWait(new MessageOptions().setPrompt( + "Ask me to choose between 'Option A' and 'Option B' using the ask_user tool. Wait for my response before continuing.")) + .get(60, TimeUnit.SECONDS); + + assertTrue(trackingExecutor.getTaskCount() > beforeSend, + "Expected the tracking executor to have been invoked for user input dispatch, " + + "but task count did not increase after sendAndWait. " + + "RpcHandlerDispatcher is not routing userInput runAsync through the provided executor."); + + session.close(); + } + } + + /** + * Verifies that hooks dispatch routes through the provided executor. + * + *

+ * When the LLM triggers a hook, the {@code RpcHandlerDispatcher} calls + * {@code CompletableFuture.runAsync(...)} to dispatch the hooks handler. + * This test asserts that dispatch goes through the caller-supplied executor. + *

+ * + * @see Snapshot: hooks/invoke_pre_tool_use_hook_when_model_runs_a_tool + */ + @Test + void testHooksDispatchUsesProvidedExecutor() throws Exception { + ctx.configureForTest("hooks", "invoke_pre_tool_use_hook_when_model_runs_a_tool"); + + TrackingExecutor trackingExecutor = new TrackingExecutor(ForkJoinPool.commonPool()); + + var config = new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setHooks(new SessionHooks().setOnPreToolUse( + (input, invocation) -> CompletableFuture.completedFuture(PreToolUseHookOutput.allow()))); + + try (CopilotClient client = new CopilotClient(createOptionsWithExecutor(trackingExecutor))) { + CopilotSession session = client.createSession(config).get(); + + Path testFile = ctx.getWorkDir().resolve("hello.txt"); + Files.writeString(testFile, "Hello from the test!"); + + int beforeSend = trackingExecutor.getTaskCount(); + + session.sendAndWait( + new MessageOptions().setPrompt("Read the contents of hello.txt and tell me what it says")) + .get(60, TimeUnit.SECONDS); + + assertTrue(trackingExecutor.getTaskCount() > beforeSend, + "Expected the tracking executor to have been invoked for hooks dispatch, " + + "but task count did not increase after sendAndWait. " + + "RpcHandlerDispatcher is not routing hooks runAsync through the provided executor."); + + session.close(); + } + } + + /** + * Verifies that {@code CopilotClient.stop()} routes session closure through + * the provided executor. + * + *

+ * {@code CopilotClient.stop()} uses + * {@code CompletableFuture.runAsync(...)} to close each active session. + * This test asserts that those closures go through the caller-supplied + * executor. + *

+ * + * @see Snapshot: tools/invokes_custom_tool + */ + @Test + void testClientStopUsesProvidedExecutor() throws Exception { + ctx.configureForTest("tools", "invokes_custom_tool"); + + TrackingExecutor trackingExecutor = new TrackingExecutor(ForkJoinPool.commonPool()); + + var parameters = new HashMap(); + var properties = new HashMap(); + var inputProp = new HashMap(); + inputProp.put("type", "string"); + inputProp.put("description", "String to encrypt"); + properties.put("input", inputProp); + parameters.put("type", "object"); + parameters.put("properties", properties); + parameters.put("required", List.of("input")); + + ToolDefinition encryptTool = ToolDefinition.create("encrypt_string", "Encrypts a string", parameters, + (invocation) -> { + Map args = invocation.getArguments(); + String input = (String) args.get("input"); + return CompletableFuture.completedFuture(input.toUpperCase()); + }); + + CopilotClient client = new CopilotClient(createOptionsWithExecutor(trackingExecutor)); + client.createSession(new SessionConfig().setTools(List.of(encryptTool)) + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get(); + + int beforeStop = trackingExecutor.getTaskCount(); + + // stop() should use the provided executor for async session closure + client.stop().get(30, TimeUnit.SECONDS); + + assertTrue(trackingExecutor.getTaskCount() > beforeStop, + "Expected the tracking executor to have been invoked during client stop, " + + "but task count did not increase. CopilotClient.stop() is not " + + "routing session closure runAsync through the provided executor."); + } +} diff --git a/src/test/java/com/github/copilot/sdk/RpcHandlerDispatcherTest.java b/src/test/java/com/github/copilot/sdk/RpcHandlerDispatcherTest.java index 61ad4dadd..79f5d7c7e 100644 --- a/src/test/java/com/github/copilot/sdk/RpcHandlerDispatcherTest.java +++ b/src/test/java/com/github/copilot/sdk/RpcHandlerDispatcherTest.java @@ -66,7 +66,7 @@ void setup() throws Exception { sessions = new ConcurrentHashMap<>(); lifecycleEvents = new CopyOnWriteArrayList<>(); - dispatcher = new RpcHandlerDispatcher(sessions, lifecycleEvents::add); + dispatcher = new RpcHandlerDispatcher(sessions, lifecycleEvents::add, null); dispatcher.registerHandlers(rpc); // Extract the registered handlers via reflection so we can invoke them directly From 31803bcb7dfcc34c0b75a8411abc5208ebaa1f7d Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Mon, 30 Mar 2026 16:59:43 -0400 Subject: [PATCH 17/80] On branch edburns/dd-2758695-virtual-threads-accept-executor modified: src/main/java/com/github/copilot/sdk/CopilotClient.java - Spotless. modified: src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java - Remove stub from TDD red phase. modified: src/site/markdown/cookbook/multiple-sessions.md - Document new feature. modified: src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java - Update test documentation. Signed-off-by: Ed Burns --- .../com/github/copilot/sdk/CopilotClient.java | 8 +-- .../sdk/json/CopilotClientOptions.java | 8 +-- .../markdown/cookbook/multiple-sessions.md | 63 +++++++++++++++++++ .../copilot/sdk/ExecutorWiringTest.java | 44 ++++++------- 4 files changed, 87 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/github/copilot/sdk/CopilotClient.java b/src/main/java/com/github/copilot/sdk/CopilotClient.java index 00dea3876..285b5fbdc 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotClient.java +++ b/src/main/java/com/github/copilot/sdk/CopilotClient.java @@ -188,8 +188,7 @@ private Connection startCoreBody() { } catch (Exception e) { String stderr = serverManager.getStderrOutput(); if (!stderr.isEmpty()) { - throw new CompletionException( - new IOException("CLI process exited unexpectedly. stderr: " + stderr, e)); + throw new CompletionException(new IOException("CLI process exited unexpectedly. stderr: " + stderr, e)); } throw new CompletionException(e); } @@ -245,9 +244,8 @@ public CompletableFuture stop() { LOG.log(Level.WARNING, "Error closing session " + session.getSessionId(), e); } }; - closeFutures.add(exec != null - ? CompletableFuture.runAsync(closeTask, exec) - : CompletableFuture.runAsync(closeTask)); + closeFutures.add( + exec != null ? CompletableFuture.runAsync(closeTask, exec) : CompletableFuture.runAsync(closeTask)); } sessions.clear(); diff --git a/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java b/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java index 33d84a9c5..af8667864 100644 --- a/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java +++ b/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java @@ -429,18 +429,14 @@ public Executor getExecutor() { *

* When provided, the SDK uses this executor for all internal * {@code CompletableFuture} combinators instead of the default - * {@code ForkJoinPool.commonPool()}. This allows callers to isolate SDK - * work onto a dedicated thread pool or integrate with container-managed - * threading. + * {@code ForkJoinPool.commonPool()}. This allows callers to isolate SDK work + * onto a dedicated thread pool or integrate with container-managed threading. * * @param executor * the executor to use, or {@code null} for the default * @return this options instance for fluent chaining */ public CopilotClientOptions setExecutor(Executor executor) { - if (null == executor) { - throw new IllegalArgumentException("PENDING(copilot): not implemented"); - } this.executor = executor; return this; } diff --git a/src/site/markdown/cookbook/multiple-sessions.md b/src/site/markdown/cookbook/multiple-sessions.md index 94a83acae..0121bfc4c 100644 --- a/src/site/markdown/cookbook/multiple-sessions.md +++ b/src/site/markdown/cookbook/multiple-sessions.md @@ -164,6 +164,69 @@ public class ParallelSessions { } ``` +## Providing a custom Executor for parallel sessions + +By default, `CompletableFuture` operations run on `ForkJoinPool.commonPool()`, +which has limited parallelism (typically `Runtime.availableProcessors() - 1` +threads). When multiple sessions block waiting for CLI responses, those threads +are unavailable for other work—a condition known as *pool starvation*. + +Use `CopilotClientOptions.setExecutor(Executor)` to supply a dedicated thread +pool so that SDK work does not compete with the rest of your application for +common-pool threads: + +```java +//DEPS com.github:copilot-sdk-java:${project.version} +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.json.CopilotClientOptions; +import com.github.copilot.sdk.json.SessionConfig; +import com.github.copilot.sdk.json.MessageOptions; +import com.github.copilot.sdk.json.PermissionHandler; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class ParallelSessionsWithExecutor { + public static void main(String[] args) throws Exception { + ExecutorService pool = Executors.newFixedThreadPool(4); + try { + var options = new CopilotClientOptions().setExecutor(pool); + try (CopilotClient client = new CopilotClient(options)) { + client.start().get(); + + var s1 = client.createSession(new SessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setModel("gpt-5")).get(); + var s2 = client.createSession(new SessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setModel("gpt-5")).get(); + var s3 = client.createSession(new SessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setModel("claude-sonnet-4.5")).get(); + + CompletableFuture.allOf( + s1.sendAndWait(new MessageOptions().setPrompt("Question 1")), + s2.sendAndWait(new MessageOptions().setPrompt("Question 2")), + s3.sendAndWait(new MessageOptions().setPrompt("Question 3")) + ).get(); + + s1.close(); + s2.close(); + s3.close(); + } + } finally { + pool.shutdown(); + } + } +} +``` + +Passing `null` (or omitting `setExecutor` entirely) keeps the default +`ForkJoinPool.commonPool()` behaviour. The executor is used for all internal +`CompletableFuture.runAsync` / `supplyAsync` calls—including client start/stop, +tool-call dispatch, permission dispatch, user-input dispatch, and hooks. + ## Use cases - **Multi-user applications**: One session per user diff --git a/src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java b/src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java index 736564139..db5b1aaf4 100644 --- a/src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java +++ b/src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java @@ -25,7 +25,6 @@ import com.github.copilot.sdk.json.CopilotClientOptions; import com.github.copilot.sdk.json.MessageOptions; 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.PreToolUseHookOutput; import com.github.copilot.sdk.json.SessionConfig; @@ -62,8 +61,8 @@ static void teardown() throws Exception { } /** - * A decorator executor that delegates to a real executor while counting - * task submissions. + * A decorator executor that delegates to a real executor while counting task + * submissions. */ static class TrackingExecutor implements Executor { @@ -101,8 +100,8 @@ private CopilotClientOptions createOptionsWithExecutor(TrackingExecutor executor * *

* {@code CopilotClient.startCore()} uses - * {@code CompletableFuture.supplyAsync(...)} to initialize the connection. - * This test asserts that the start-up task goes through the caller-supplied + * {@code CompletableFuture.supplyAsync(...)} to initialize the connection. This + * test asserts that the start-up task goes through the caller-supplied * executor, not {@code ForkJoinPool.commonPool()}. *

* @@ -129,9 +128,8 @@ void testClientStartUsesProvidedExecutor() throws Exception { * Verifies that tool call dispatch routes through the provided executor. * *

- * When a custom tool is invoked by the LLM, the - * {@code RpcHandlerDispatcher} calls - * {@code CompletableFuture.runAsync(...)} to dispatch the tool handler. + * When a custom tool is invoked by the LLM, the {@code RpcHandlerDispatcher} + * calls {@code CompletableFuture.runAsync(...)} to dispatch the tool handler. * This test asserts that dispatch goes through the caller-supplied executor. *

* @@ -187,10 +185,9 @@ void testToolCallDispatchUsesProvidedExecutor() throws Exception { * executor. * *

- * When the LLM requests a permission, the {@code RpcHandlerDispatcher} - * calls {@code CompletableFuture.runAsync(...)} to dispatch the permission - * handler. This test asserts that dispatch goes through the caller-supplied - * executor. + * When the LLM requests a permission, the {@code RpcHandlerDispatcher} calls + * {@code CompletableFuture.runAsync(...)} to dispatch the permission handler. + * This test asserts that dispatch goes through the caller-supplied executor. *

* * @see Snapshot: permissions/permission_handler_for_write_operations @@ -212,8 +209,7 @@ void testPermissionDispatchUsesProvidedExecutor() throws Exception { int beforeSend = trackingExecutor.getTaskCount(); - session.sendAndWait( - new MessageOptions().setPrompt("Edit test.txt and replace 'original' with 'modified'")) + session.sendAndWait(new MessageOptions().setPrompt("Edit test.txt and replace 'original' with 'modified'")) .get(60, TimeUnit.SECONDS); assertTrue(trackingExecutor.getTaskCount() > beforeSend, @@ -231,9 +227,8 @@ void testPermissionDispatchUsesProvidedExecutor() throws Exception { * *

* When the LLM asks for user input, the {@code RpcHandlerDispatcher} calls - * {@code CompletableFuture.runAsync(...)} to dispatch the user input - * handler. This test asserts that dispatch goes through the caller-supplied - * executor. + * {@code CompletableFuture.runAsync(...)} to dispatch the user input handler. + * This test asserts that dispatch goes through the caller-supplied executor. *

* * @see Snapshot: @@ -278,8 +273,8 @@ void testUserInputDispatchUsesProvidedExecutor() throws Exception { * *

* When the LLM triggers a hook, the {@code RpcHandlerDispatcher} calls - * {@code CompletableFuture.runAsync(...)} to dispatch the hooks handler. - * This test asserts that dispatch goes through the caller-supplied executor. + * {@code CompletableFuture.runAsync(...)} to dispatch the hooks handler. This + * test asserts that dispatch goes through the caller-supplied executor. *

* * @see Snapshot: hooks/invoke_pre_tool_use_hook_when_model_runs_a_tool @@ -316,14 +311,13 @@ void testHooksDispatchUsesProvidedExecutor() throws Exception { } /** - * Verifies that {@code CopilotClient.stop()} routes session closure through - * the provided executor. + * Verifies that {@code CopilotClient.stop()} routes session closure through the + * provided executor. * *

- * {@code CopilotClient.stop()} uses - * {@code CompletableFuture.runAsync(...)} to close each active session. - * This test asserts that those closures go through the caller-supplied - * executor. + * {@code CopilotClient.stop()} uses {@code CompletableFuture.runAsync(...)} to + * close each active session. This test asserts that those closures go through + * the caller-supplied executor. *

* * @see Snapshot: tools/invokes_custom_tool From e62485739e973ce899cbf57396a43ad4cfc47be0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 30 Mar 2026 21:19:56 +0000 Subject: [PATCH 18/80] Remove "TDD red-phase" from ExecutorWiringTest Javadoc Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/93199b25-7c90-4c45-9540-527396b8990c Co-authored-by: edburns <75821+edburns@users.noreply.github.com> --- src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java b/src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java index db5b1aaf4..15904504a 100644 --- a/src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java +++ b/src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java @@ -33,7 +33,7 @@ import com.github.copilot.sdk.json.UserInputResponse; /** - * TDD red-phase tests verifying that when an {@link Executor} is provided via + * Tests verifying that when an {@link Executor} is provided via * {@link CopilotClientOptions#setExecutor(Executor)}, all internal * {@code CompletableFuture.*Async} calls are routed through that executor * instead of {@code ForkJoinPool.commonPool()}. From e975d6cf420547ecbc89ce1ae6a7cdf518e6e330 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 30 Mar 2026 21:53:47 +0000 Subject: [PATCH 19/80] Handle RejectedExecutionException in all async submission sites Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/63b9b09f-f1f4-44d3-8e34-ad01e355cc6a Co-authored-by: edburns <75821+edburns@users.noreply.github.com> --- .../com/github/copilot/sdk/CopilotClient.java | 24 +++++++++++++---- .../github/copilot/sdk/CopilotSession.java | 27 +++++++++++++------ .../copilot/sdk/RpcHandlerDispatcher.java | 14 +++++++--- 3 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/github/copilot/sdk/CopilotClient.java b/src/main/java/com/github/copilot/sdk/CopilotClient.java index 285b5fbdc..e2790f6a3 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotClient.java +++ b/src/main/java/com/github/copilot/sdk/CopilotClient.java @@ -14,6 +14,7 @@ import java.util.concurrent.CompletionException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; @@ -152,9 +153,13 @@ private CompletableFuture startCore() { LOG.fine("Starting Copilot client"); Executor exec = options.getExecutor(); - return exec != null - ? CompletableFuture.supplyAsync(this::startCoreBody, exec) - : CompletableFuture.supplyAsync(this::startCoreBody); + try { + return exec != null + ? CompletableFuture.supplyAsync(this::startCoreBody, exec) + : CompletableFuture.supplyAsync(this::startCoreBody); + } catch (RejectedExecutionException e) { + return CompletableFuture.failedFuture(e); + } } private Connection startCoreBody() { @@ -244,8 +249,17 @@ public CompletableFuture stop() { LOG.log(Level.WARNING, "Error closing session " + session.getSessionId(), e); } }; - closeFutures.add( - exec != null ? CompletableFuture.runAsync(closeTask, exec) : CompletableFuture.runAsync(closeTask)); + CompletableFuture future; + try { + future = exec != null + ? CompletableFuture.runAsync(closeTask, exec) + : CompletableFuture.runAsync(closeTask); + } catch (RejectedExecutionException e) { + LOG.log(Level.WARNING, "Executor rejected session close task; closing inline", e); + closeTask.run(); + future = CompletableFuture.completedFuture(null); + } + closeFutures.add(future); } sessions.clear(); diff --git a/src/main/java/com/github/copilot/sdk/CopilotSession.java b/src/main/java/com/github/copilot/sdk/CopilotSession.java index 485c39312..23b54ed2d 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotSession.java +++ b/src/main/java/com/github/copilot/sdk/CopilotSession.java @@ -730,10 +730,15 @@ private void executeToolAndRespondAsync(String requestId, String toolName, Strin } } }; - if (executor != null) { - CompletableFuture.runAsync(task, executor); - } else { - CompletableFuture.runAsync(task); + try { + if (executor != null) { + CompletableFuture.runAsync(task, executor); + } else { + CompletableFuture.runAsync(task); + } + } catch (RejectedExecutionException e) { + LOG.log(Level.WARNING, "Executor rejected tool task for requestId=" + requestId + "; running inline", e); + task.run(); } } @@ -783,10 +788,16 @@ private void executePermissionAndRespondAsync(String requestId, PermissionReques } } }; - if (executor != null) { - CompletableFuture.runAsync(task, executor); - } else { - CompletableFuture.runAsync(task); + try { + if (executor != null) { + CompletableFuture.runAsync(task, executor); + } else { + CompletableFuture.runAsync(task); + } + } catch (RejectedExecutionException e) { + LOG.log(Level.WARNING, "Executor rejected permission task for requestId=" + requestId + "; running inline", + e); + task.run(); } } diff --git a/src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java b/src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java index 9f55938af..f1d488105 100644 --- a/src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java +++ b/src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java @@ -10,6 +10,7 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; import java.util.logging.Level; import java.util.logging.Logger; @@ -367,10 +368,15 @@ private void handleSystemMessageTransform(JsonRpcClient rpc, String requestId, J } private void runAsync(Runnable task) { - if (executor != null) { - CompletableFuture.runAsync(task, executor); - } else { - CompletableFuture.runAsync(task); + try { + if (executor != null) { + CompletableFuture.runAsync(task, executor); + } else { + CompletableFuture.runAsync(task); + } + } catch (RejectedExecutionException e) { + LOG.log(Level.WARNING, "Executor rejected handler task; running inline", e); + task.run(); } } } From 63b6d31bd8d6bc516fcfe5f44144728fe1053dd2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 30 Mar 2026 21:56:13 +0000 Subject: [PATCH 20/80] Align RejectedExecutionException log message formatting in CopilotSession Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/63b9b09f-f1f4-44d3-8e34-ad01e355cc6a Co-authored-by: edburns <75821+edburns@users.noreply.github.com> --- src/main/java/com/github/copilot/sdk/CopilotSession.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/github/copilot/sdk/CopilotSession.java b/src/main/java/com/github/copilot/sdk/CopilotSession.java index 23b54ed2d..523da1114 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotSession.java +++ b/src/main/java/com/github/copilot/sdk/CopilotSession.java @@ -795,8 +795,7 @@ private void executePermissionAndRespondAsync(String requestId, PermissionReques CompletableFuture.runAsync(task); } } catch (RejectedExecutionException e) { - LOG.log(Level.WARNING, "Executor rejected permission task for requestId=" + requestId + "; running inline", - e); + LOG.log(Level.WARNING, "Executor rejected perm task for requestId=" + requestId + "; running inline", e); task.run(); } } From 7728b4f65bc396eddcd55a776ef27730c0a1d9b4 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Mon, 30 Mar 2026 19:17:00 -0400 Subject: [PATCH 21/80] On branch edburns/dd-2758695-virtual-threads-accept-executor modified: README.md - Use the "uncomment these three lines to get Virtual Threads" approach modified: src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java - Cleanup. Sorting. Signed-off-by: Ed Burns --- README.md | 9 +- .../sdk/json/CopilotClientOptions.java | 342 +++++++++--------- 2 files changed, 179 insertions(+), 172 deletions(-) diff --git a/README.md b/README.md index 0084eb417..84f0d6d81 100644 --- a/README.md +++ b/README.md @@ -69,16 +69,23 @@ implementation 'com.github:copilot-sdk-java:0.2.1-java.0' import com.github.copilot.sdk.CopilotClient; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.events.SessionUsageInfoEvent; +import com.github.copilot.sdk.json.CopilotClientOptions; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.SessionConfig; +import java.util.concurrent.Executors; + public class CopilotSDK { public static void main(String[] args) throws Exception { var lastMessage = new String[]{null}; // Create and start client - try (var client = new CopilotClient()) { + try (var client = new CopilotClient()) { // JDK 25+: comment out this line + // JDK 25+: uncomment the following 3 lines for virtual thread support + // var options = new CopilotClientOptions() + // .setExecutor(Executors.newVirtualThreadPerTaskExecutor()); + // try (var client = new CopilotClient(options)) { client.start().get(); // Create a session diff --git a/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java b/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java index af8667864..3ba9fb0a0 100644 --- a/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java +++ b/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java @@ -35,133 +35,115 @@ @JsonInclude(JsonInclude.Include.NON_NULL) public class CopilotClientOptions { - private String cliPath; - private String[] cliArgs; - private String cwd; - private int port; - private boolean useStdio = true; - private String cliUrl; - private String logLevel = "info"; - private boolean autoStart = true; @Deprecated private boolean autoRestart; + private boolean autoStart = true; + private String[] cliArgs; + private String cliPath; + private String cliUrl; + private String cwd; private Map environment; + private Executor executor; private String gitHubToken; - private Boolean useLoggedInUser; + private String logLevel = "info"; private Supplier>> onListModels; + private int port; private TelemetryConfig telemetry; - private Executor executor; - - /** - * Gets the path to the Copilot CLI executable. - * - * @return the CLI path, or {@code null} to use "copilot" from PATH - */ - public String getCliPath() { - return cliPath; - } - - /** - * Sets the path to the Copilot CLI executable. - * - * @param cliPath - * the path to the CLI executable, or {@code null} to use "copilot" - * from PATH - * @return this options instance for method chaining - */ - public CopilotClientOptions setCliPath(String cliPath) { - this.cliPath = cliPath; - return this; - } + private Boolean useLoggedInUser; + private boolean useStdio = true; /** - * Gets the extra CLI arguments. + * Returns whether the client should automatically restart the server on crash. * - * @return the extra arguments to pass to the CLI + * @return the auto-restart flag value (no longer has any effect) + * @deprecated This option has no effect and will be removed in a future + * release. */ - public String[] getCliArgs() { - return cliArgs; + @Deprecated + public boolean isAutoRestart() { + return autoRestart; } /** - * Sets extra arguments to pass to the CLI process. - *

- * These arguments are prepended before SDK-managed flags. + * Sets whether the client should automatically restart the CLI server if it + * crashes unexpectedly. * - * @param cliArgs - * the extra arguments to pass + * @param autoRestart + * ignored — this option no longer has any effect * @return this options instance for method chaining + * @deprecated This option has no effect and will be removed in a future + * release. */ - public CopilotClientOptions setCliArgs(String[] cliArgs) { - this.cliArgs = cliArgs; + @Deprecated + public CopilotClientOptions setAutoRestart(boolean autoRestart) { + this.autoRestart = autoRestart; return this; } /** - * Gets the working directory for the CLI process. + * Returns whether the client should automatically start the server. * - * @return the working directory path + * @return {@code true} to auto-start (default), {@code false} for manual start */ - public String getCwd() { - return cwd; + public boolean isAutoStart() { + return autoStart; } /** - * Sets the working directory for the CLI process. + * Sets whether the client should automatically start the CLI server when the + * first request is made. * - * @param cwd - * the working directory path + * @param autoStart + * {@code true} to auto-start, {@code false} for manual start * @return this options instance for method chaining */ - public CopilotClientOptions setCwd(String cwd) { - this.cwd = cwd; + public CopilotClientOptions setAutoStart(boolean autoStart) { + this.autoStart = autoStart; return this; } /** - * Gets the TCP port for the CLI server. + * Gets the extra CLI arguments. * - * @return the port number, or 0 for a random port + * @return the extra arguments to pass to the CLI */ - public int getPort() { - return port; + public String[] getCliArgs() { + return cliArgs; } /** - * Sets the TCP port for the CLI server to listen on. + * Sets extra arguments to pass to the CLI process. *

- * This is only used when {@link #isUseStdio()} is {@code false}. + * These arguments are prepended before SDK-managed flags. * - * @param port - * the port number, or 0 for a random port + * @param cliArgs + * the extra arguments to pass * @return this options instance for method chaining */ - public CopilotClientOptions setPort(int port) { - this.port = port; + public CopilotClientOptions setCliArgs(String[] cliArgs) { + this.cliArgs = cliArgs; return this; } /** - * Returns whether to use stdio transport instead of TCP. + * Gets the path to the Copilot CLI executable. * - * @return {@code true} to use stdio (default), {@code false} to use TCP + * @return the CLI path, or {@code null} to use "copilot" from PATH */ - public boolean isUseStdio() { - return useStdio; + public String getCliPath() { + return cliPath; } /** - * Sets whether to use stdio transport instead of TCP. - *

- * Stdio transport is more efficient and is the default. TCP transport can be - * useful for debugging or connecting to remote servers. + * Sets the path to the Copilot CLI executable. * - * @param useStdio - * {@code true} to use stdio, {@code false} to use TCP + * @param cliPath + * the path to the CLI executable, or {@code null} to use "copilot" + * from PATH * @return this options instance for method chaining */ - public CopilotClientOptions setUseStdio(boolean useStdio) { - this.useStdio = useStdio; + public CopilotClientOptions setCliPath(String cliPath) { + this.cliPath = cliPath; return this; } @@ -193,98 +175,73 @@ public CopilotClientOptions setCliUrl(String cliUrl) { } /** - * Gets the log level for the CLI process. - * - * @return the log level (default: "info") - */ - public String getLogLevel() { - return logLevel; - } - - /** - * Sets the log level for the CLI process. - *

- * Valid levels include: "error", "warn", "info", "debug", "trace". - * - * @param logLevel - * the log level - * @return this options instance for method chaining - */ - public CopilotClientOptions setLogLevel(String logLevel) { - this.logLevel = logLevel; - return this; - } - - /** - * Returns whether the client should automatically start the server. + * Gets the working directory for the CLI process. * - * @return {@code true} to auto-start (default), {@code false} for manual start + * @return the working directory path */ - public boolean isAutoStart() { - return autoStart; + public String getCwd() { + return cwd; } /** - * Sets whether the client should automatically start the CLI server when the - * first request is made. + * Sets the working directory for the CLI process. * - * @param autoStart - * {@code true} to auto-start, {@code false} for manual start + * @param cwd + * the working directory path * @return this options instance for method chaining */ - public CopilotClientOptions setAutoStart(boolean autoStart) { - this.autoStart = autoStart; + public CopilotClientOptions setCwd(String cwd) { + this.cwd = cwd; return this; } /** - * Returns whether the client should automatically restart the server on crash. + * Gets the environment variables for the CLI process. * - * @return the auto-restart flag value (no longer has any effect) - * @deprecated This option has no effect and will be removed in a future - * release. + * @return the environment variables map */ - @Deprecated - public boolean isAutoRestart() { - return autoRestart; + public Map getEnvironment() { + return environment; } /** - * Sets whether the client should automatically restart the CLI server if it - * crashes unexpectedly. + * Sets environment variables to pass to the CLI process. + *

+ * When set, these environment variables replace the inherited environment. * - * @param autoRestart - * ignored — this option no longer has any effect + * @param environment + * the environment variables map * @return this options instance for method chaining - * @deprecated This option has no effect and will be removed in a future - * release. */ - @Deprecated - public CopilotClientOptions setAutoRestart(boolean autoRestart) { - this.autoRestart = autoRestart; + public CopilotClientOptions setEnvironment(Map environment) { + this.environment = environment; return this; } /** - * Gets the environment variables for the CLI process. + * Gets the executor used for internal asynchronous operations. * - * @return the environment variables map + * @return the executor, or {@code null} to use the default + * {@code ForkJoinPool.commonPool()} */ - public Map getEnvironment() { - return environment; + public Executor getExecutor() { + return executor; } /** - * Sets environment variables to pass to the CLI process. + * Sets the executor used for internal asynchronous operations. *

- * When set, these environment variables replace the inherited environment. + * When provided, the SDK uses this executor for all internal + * {@code CompletableFuture} combinators instead of the default + * {@code ForkJoinPool.commonPool()}. This allows callers to isolate SDK work + * onto a dedicated thread pool or integrate with container-managed threading. * - * @param environment - * the environment variables map - * @return this options instance for method chaining + * @param executor + * the executor to use, or {@code null} for the default + * @return this options instance for fluent chaining */ - public CopilotClientOptions setEnvironment(Map environment) { - this.environment = environment; + public CopilotClientOptions setExecutor(Executor executor) { + this.executor = executor; return this; } @@ -338,28 +295,25 @@ public CopilotClientOptions setGithubToken(String githubToken) { } /** - * Returns whether to use the logged-in user for authentication. + * Gets the log level for the CLI process. * - * @return {@code true} to use logged-in user auth, {@code false} to use only - * explicit tokens, or {@code null} to use default behavior + * @return the log level (default: "info") */ - public Boolean getUseLoggedInUser() { - return useLoggedInUser; + public String getLogLevel() { + return logLevel; } /** - * Sets whether to use the logged-in user for authentication. + * Sets the log level for the CLI process. *

- * When true, the CLI server will attempt to use stored OAuth tokens or gh CLI - * auth. When false, only explicit tokens (gitHubToken or environment variables) - * are used. Default: true (but defaults to false when gitHubToken is provided). + * Valid levels include: "error", "warn", "info", "debug", "trace". * - * @param useLoggedInUser - * {@code true} to use logged-in user auth, {@code false} otherwise + * @param logLevel + * the log level * @return this options instance for method chaining */ - public CopilotClientOptions setUseLoggedInUser(Boolean useLoggedInUser) { - this.useLoggedInUser = useLoggedInUser; + public CopilotClientOptions setLogLevel(String logLevel) { + this.logLevel = logLevel; return this; } @@ -388,6 +342,29 @@ public CopilotClientOptions setOnListModels(Supplier + * This is only used when {@link #isUseStdio()} is {@code false}. + * + * @param port + * the port number, or 0 for a random port + * @return this options instance for method chaining + */ + public CopilotClientOptions setPort(int port) { + this.port = port; + return this; + } + /** * Gets the OpenTelemetry configuration for the CLI server. * @@ -415,29 +392,52 @@ public CopilotClientOptions setTelemetry(TelemetryConfig telemetry) { } /** - * Gets the executor used for internal asynchronous operations. + * Returns whether to use the logged-in user for authentication. * - * @return the executor, or {@code null} to use the default - * {@code ForkJoinPool.commonPool()} + * @return {@code true} to use logged-in user auth, {@code false} to use only + * explicit tokens, or {@code null} to use default behavior */ - public Executor getExecutor() { - return executor; + public Boolean getUseLoggedInUser() { + return useLoggedInUser; } /** - * Sets the executor used for internal asynchronous operations. + * Sets whether to use the logged-in user for authentication. *

- * When provided, the SDK uses this executor for all internal - * {@code CompletableFuture} combinators instead of the default - * {@code ForkJoinPool.commonPool()}. This allows callers to isolate SDK work - * onto a dedicated thread pool or integrate with container-managed threading. + * When true, the CLI server will attempt to use stored OAuth tokens or gh CLI + * auth. When false, only explicit tokens (gitHubToken or environment variables) + * are used. Default: true (but defaults to false when gitHubToken is provided). * - * @param executor - * the executor to use, or {@code null} for the default - * @return this options instance for fluent chaining + * @param useLoggedInUser + * {@code true} to use logged-in user auth, {@code false} otherwise + * @return this options instance for method chaining */ - public CopilotClientOptions setExecutor(Executor executor) { - this.executor = executor; + public CopilotClientOptions setUseLoggedInUser(Boolean useLoggedInUser) { + this.useLoggedInUser = useLoggedInUser; + return this; + } + + /** + * Returns whether to use stdio transport instead of TCP. + * + * @return {@code true} to use stdio (default), {@code false} to use TCP + */ + public boolean isUseStdio() { + return useStdio; + } + + /** + * Sets whether to use stdio transport instead of TCP. + *

+ * Stdio transport is more efficient and is the default. TCP transport can be + * useful for debugging or connecting to remote servers. + * + * @param useStdio + * {@code true} to use stdio, {@code false} to use TCP + * @return this options instance for method chaining + */ + public CopilotClientOptions setUseStdio(boolean useStdio) { + this.useStdio = useStdio; return this; } @@ -454,21 +454,21 @@ public CopilotClientOptions setExecutor(Executor executor) { @Override public CopilotClientOptions clone() { CopilotClientOptions copy = new CopilotClientOptions(); - copy.cliPath = this.cliPath; + copy.autoRestart = this.autoRestart; + copy.autoStart = this.autoStart; copy.cliArgs = this.cliArgs != null ? this.cliArgs.clone() : null; - copy.cwd = this.cwd; - copy.port = this.port; - copy.useStdio = this.useStdio; + copy.cliPath = this.cliPath; copy.cliUrl = this.cliUrl; - copy.logLevel = this.logLevel; - copy.autoStart = this.autoStart; - copy.autoRestart = this.autoRestart; + copy.cwd = this.cwd; copy.environment = this.environment != null ? new java.util.HashMap<>(this.environment) : null; + copy.executor = this.executor; copy.gitHubToken = this.gitHubToken; - copy.useLoggedInUser = this.useLoggedInUser; + copy.logLevel = this.logLevel; copy.onListModels = this.onListModels; + copy.port = this.port; copy.telemetry = this.telemetry; - copy.executor = this.executor; + copy.useLoggedInUser = this.useLoggedInUser; + copy.useStdio = this.useStdio; return copy; } } From 1721ffc78104f7988ef8e85adb282f09e2c72f04 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 31 Mar 2026 16:42:11 +0000 Subject: [PATCH 22/80] Add null checks to all reference-type setters in CopilotClientOptions Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/019cc9a8-a29a-49a5-a7ac-aa573931dfb8 Co-authored-by: edburns <75821+edburns@users.noreply.github.com> --- .../sdk/json/CopilotClientOptions.java | 32 +++++++++---------- .../copilot/sdk/CliServerManagerTest.java | 4 +-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java b/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java index 3ba9fb0a0..ecba8ce82 100644 --- a/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java +++ b/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.function.Supplier; @@ -121,7 +122,7 @@ public String[] getCliArgs() { * @return this options instance for method chaining */ public CopilotClientOptions setCliArgs(String[] cliArgs) { - this.cliArgs = cliArgs; + this.cliArgs = Objects.requireNonNull(cliArgs, "cliArgs must not be null"); return this; } @@ -138,12 +139,11 @@ public String getCliPath() { * Sets the path to the Copilot CLI executable. * * @param cliPath - * the path to the CLI executable, or {@code null} to use "copilot" - * from PATH + * the path to the CLI executable * @return this options instance for method chaining */ public CopilotClientOptions setCliPath(String cliPath) { - this.cliPath = cliPath; + this.cliPath = Objects.requireNonNull(cliPath, "cliPath must not be null"); return this; } @@ -170,7 +170,7 @@ public String getCliUrl() { * @return this options instance for method chaining */ public CopilotClientOptions setCliUrl(String cliUrl) { - this.cliUrl = cliUrl; + this.cliUrl = Objects.requireNonNull(cliUrl, "cliUrl must not be null"); return this; } @@ -191,7 +191,7 @@ public String getCwd() { * @return this options instance for method chaining */ public CopilotClientOptions setCwd(String cwd) { - this.cwd = cwd; + this.cwd = Objects.requireNonNull(cwd, "cwd must not be null"); return this; } @@ -214,7 +214,7 @@ public Map getEnvironment() { * @return this options instance for method chaining */ public CopilotClientOptions setEnvironment(Map environment) { - this.environment = environment; + this.environment = Objects.requireNonNull(environment, "environment must not be null"); return this; } @@ -237,11 +237,11 @@ public Executor getExecutor() { * onto a dedicated thread pool or integrate with container-managed threading. * * @param executor - * the executor to use, or {@code null} for the default + * the executor to use * @return this options instance for fluent chaining */ public CopilotClientOptions setExecutor(Executor executor) { - this.executor = executor; + this.executor = Objects.requireNonNull(executor, "executor must not be null"); return this; } @@ -265,7 +265,7 @@ public String getGitHubToken() { * @return this options instance for method chaining */ public CopilotClientOptions setGitHubToken(String gitHubToken) { - this.gitHubToken = gitHubToken; + this.gitHubToken = Objects.requireNonNull(gitHubToken, "gitHubToken must not be null"); return this; } @@ -290,7 +290,7 @@ public String getGithubToken() { */ @Deprecated public CopilotClientOptions setGithubToken(String githubToken) { - this.gitHubToken = githubToken; + this.gitHubToken = Objects.requireNonNull(githubToken, "githubToken must not be null"); return this; } @@ -313,7 +313,7 @@ public String getLogLevel() { * @return this options instance for method chaining */ public CopilotClientOptions setLogLevel(String logLevel) { - this.logLevel = logLevel; + this.logLevel = Objects.requireNonNull(logLevel, "logLevel must not be null"); return this; } @@ -338,7 +338,7 @@ public Supplier>> getOnListModels() { * @return this options instance for method chaining */ public CopilotClientOptions setOnListModels(Supplier>> onListModels) { - this.onListModels = onListModels; + this.onListModels = Objects.requireNonNull(onListModels, "onListModels must not be null"); return this; } @@ -378,8 +378,8 @@ public TelemetryConfig getTelemetry() { /** * Sets the OpenTelemetry configuration for the CLI server. *

- * When set to a non-{@code null} value, the CLI server is started with - * OpenTelemetry instrumentation enabled using the provided settings. + * When set, the CLI server is started with OpenTelemetry instrumentation + * enabled using the provided settings. * * @param telemetry * the telemetry configuration @@ -387,7 +387,7 @@ public TelemetryConfig getTelemetry() { * @since 1.2.0 */ public CopilotClientOptions setTelemetry(TelemetryConfig telemetry) { - this.telemetry = telemetry; + this.telemetry = Objects.requireNonNull(telemetry, "telemetry must not be null"); return this; } diff --git a/src/test/java/com/github/copilot/sdk/CliServerManagerTest.java b/src/test/java/com/github/copilot/sdk/CliServerManagerTest.java index 86d6be875..f17201583 100644 --- a/src/test/java/com/github/copilot/sdk/CliServerManagerTest.java +++ b/src/test/java/com/github/copilot/sdk/CliServerManagerTest.java @@ -199,8 +199,8 @@ void startCliServerWithGitHubTokenAndNoExplicitUseLoggedInUser() throws Exceptio @Test void startCliServerWithNullCliPath() throws Exception { - // Test the null cliPath branch (defaults to "copilot") - var options = new CopilotClientOptions().setCliPath(null).setUseStdio(true); + // Test the default cliPath branch (defaults to "copilot" when not set) + var options = new CopilotClientOptions().setUseStdio(true); var manager = new CliServerManager(options); // "copilot" likely doesn't exist in the test env — that's fine From 11aa5d65e300f50e510d6f484e72754d00d873e0 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Tue, 31 Mar 2026 14:10:44 -0400 Subject: [PATCH 23/80] On branch edburns/dd-2758695-virtual-threads-accept-executor modified: src/main/java/com/github/copilot/sdk/CopilotSession.java modified: src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java - Spotless apply. - Sync javadoc to behavior. --- .../github/copilot/sdk/CopilotSession.java | 1 - .../sdk/json/CopilotClientOptions.java | 73 ++++++++++++++----- 2 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/github/copilot/sdk/CopilotSession.java b/src/main/java/com/github/copilot/sdk/CopilotSession.java index 523da1114..844737fc2 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotSession.java +++ b/src/main/java/com/github/copilot/sdk/CopilotSession.java @@ -14,7 +14,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; -import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; diff --git a/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java b/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java index ecba8ce82..9470cd05f 100644 --- a/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java +++ b/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java @@ -4,6 +4,8 @@ package com.github.copilot.sdk.json; +import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -105,24 +107,35 @@ public CopilotClientOptions setAutoStart(boolean autoStart) { /** * Gets the extra CLI arguments. + *

+ * Returns a shallow copy of the internal array, or {@code null} if no arguments + * have been set. * - * @return the extra arguments to pass to the CLI + * @return a copy of the extra arguments, or {@code null} */ public String[] getCliArgs() { - return cliArgs; + return cliArgs != null ? Arrays.copyOf(cliArgs, cliArgs.length) : null; } /** * Sets extra arguments to pass to the CLI process. *

- * These arguments are prepended before SDK-managed flags. + * These arguments are prepended before SDK-managed flags. A shallow copy of the + * provided array is stored. If {@code null} or empty, the existing arguments + * are cleared. * * @param cliArgs - * the extra arguments to pass + * the extra arguments to pass, or {@code null}/empty to clear * @return this options instance for method chaining */ public CopilotClientOptions setCliArgs(String[] cliArgs) { - this.cliArgs = Objects.requireNonNull(cliArgs, "cliArgs must not be null"); + if (cliArgs == null || cliArgs.length == 0) { + if (this.cliArgs != null) { + this.cliArgs = new String[0]; + } + } else { + this.cliArgs = Arrays.copyOf(cliArgs, cliArgs.length); + } return this; } @@ -166,8 +179,11 @@ public String getCliUrl() { * {@link #setUseStdio(boolean)} and {@link #setCliPath(String)}. * * @param cliUrl - * the CLI server URL to connect to + * the CLI server URL to connect to (must not be {@code null} or + * empty) * @return this options instance for method chaining + * @throws IllegalArgumentException + * if {@code cliUrl} is {@code null} or empty */ public CopilotClientOptions setCliUrl(String cliUrl) { this.cliUrl = Objects.requireNonNull(cliUrl, "cliUrl must not be null"); @@ -187,8 +203,10 @@ public String getCwd() { * Sets the working directory for the CLI process. * * @param cwd - * the working directory path + * the working directory path (must not be {@code null} or empty) * @return this options instance for method chaining + * @throws IllegalArgumentException + * if {@code cwd} is {@code null} or empty */ public CopilotClientOptions setCwd(String cwd) { this.cwd = Objects.requireNonNull(cwd, "cwd must not be null"); @@ -197,24 +215,35 @@ public CopilotClientOptions setCwd(String cwd) { /** * Gets the environment variables for the CLI process. + *

+ * Returns a shallow copy of the internal map, or {@code null} if no environment + * has been set. * - * @return the environment variables map + * @return a copy of the environment variables map, or {@code null} */ public Map getEnvironment() { - return environment; + return environment != null ? new HashMap<>(environment) : null; } /** * Sets environment variables to pass to the CLI process. *

- * When set, these environment variables replace the inherited environment. + * When set, these environment variables replace the inherited environment. A + * shallow copy of the provided map is stored. If {@code null} or empty, the + * existing environment is cleared. * * @param environment - * the environment variables map + * the environment variables map, or {@code null}/empty to clear * @return this options instance for method chaining */ public CopilotClientOptions setEnvironment(Map environment) { - this.environment = Objects.requireNonNull(environment, "environment must not be null"); + if (environment == null || environment.isEmpty()) { + if (this.environment != null) { + this.environment.clear(); + } + } else { + this.environment = new HashMap<>(environment); + } return this; } @@ -261,8 +290,10 @@ public String getGitHubToken() { * variable. This takes priority over other authentication methods. * * @param gitHubToken - * the GitHub token + * the GitHub token (must not be {@code null} or empty) * @return this options instance for method chaining + * @throws IllegalArgumentException + * if {@code gitHubToken} is {@code null} or empty */ public CopilotClientOptions setGitHubToken(String gitHubToken) { this.gitHubToken = Objects.requireNonNull(gitHubToken, "gitHubToken must not be null"); @@ -309,8 +340,10 @@ public String getLogLevel() { * Valid levels include: "error", "warn", "info", "debug", "trace". * * @param logLevel - * the log level + * the log level (must not be {@code null} or empty) * @return this options instance for method chaining + * @throws IllegalArgumentException + * if {@code logLevel} is {@code null} or empty */ public CopilotClientOptions setLogLevel(String logLevel) { this.logLevel = Objects.requireNonNull(logLevel, "logLevel must not be null"); @@ -334,8 +367,11 @@ public Supplier>> getOnListModels() { * available from your custom provider. * * @param onListModels - * the handler that returns the list of available models + * the handler that returns the list of available models (must not be + * {@code null}) * @return this options instance for method chaining + * @throws IllegalArgumentException + * if {@code onListModels} is {@code null} */ public CopilotClientOptions setOnListModels(Supplier>> onListModels) { this.onListModels = Objects.requireNonNull(onListModels, "onListModels must not be null"); @@ -407,13 +443,16 @@ public Boolean getUseLoggedInUser() { * When true, the CLI server will attempt to use stored OAuth tokens or gh CLI * auth. When false, only explicit tokens (gitHubToken or environment variables) * are used. Default: true (but defaults to false when gitHubToken is provided). + *

+ * Passing {@code null} is equivalent to passing {@link Boolean#FALSE}. * * @param useLoggedInUser - * {@code true} to use logged-in user auth, {@code false} otherwise + * {@code true} to use logged-in user auth, {@code false} or + * {@code null} otherwise * @return this options instance for method chaining */ public CopilotClientOptions setUseLoggedInUser(Boolean useLoggedInUser) { - this.useLoggedInUser = useLoggedInUser; + this.useLoggedInUser = useLoggedInUser != null ? useLoggedInUser : Boolean.FALSE; return this; } From 4fdef27df41fba977ffff7bfb58ed1e296b07299 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Tue, 31 Mar 2026 14:31:33 -0400 Subject: [PATCH 24/80] On branch edburns/dd-2758695-virtual-threads-accept-executor modified: src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java - Correctly implement the semantic of "null argument to setExecutor means use the default executor." modified: src/test/java/com/github/copilot/sdk/ConfigCloneTest.java - Adjust test based on defensive copy changes. --- .../sdk/json/CopilotClientOptions.java | 7 +++++-- .../github/copilot/sdk/ConfigCloneTest.java | 19 ++++++++++++++----- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java b/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java index 9470cd05f..2e9a80456 100644 --- a/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java +++ b/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java @@ -264,13 +264,16 @@ public Executor getExecutor() { * {@code CompletableFuture} combinators instead of the default * {@code ForkJoinPool.commonPool()}. This allows callers to isolate SDK work * onto a dedicated thread pool or integrate with container-managed threading. + *

+ * Passing {@code null} reverts to the default {@code ForkJoinPool.commonPool()} + * behavior. * * @param executor - * the executor to use + * the executor to use, or {@code null} for the default * @return this options instance for fluent chaining */ public CopilotClientOptions setExecutor(Executor executor) { - this.executor = Objects.requireNonNull(executor, "executor must not be null"); + this.executor = executor; return this; } diff --git a/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java b/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java index f3eceb4c2..bf4881d5c 100644 --- a/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java +++ b/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java @@ -49,10 +49,16 @@ void copilotClientOptionsArrayIndependence() { original.setCliArgs(args); CopilotClientOptions cloned = original.clone(); - cloned.getCliArgs()[0] = "--changed"; + // Mutate the source array after set — should not affect original or clone + args[0] = "--changed"; + + assertEquals("--flag1", original.getCliArgs()[0]); + assertEquals("--flag1", cloned.getCliArgs()[0]); + + // getCliArgs() returns a copy, so mutating it should not affect internals + original.getCliArgs()[0] = "--mutated"; assertEquals("--flag1", original.getCliArgs()[0]); - assertEquals("--changed", cloned.getCliArgs()[0]); } @Test @@ -64,12 +70,15 @@ void copilotClientOptionsEnvironmentIndependence() { CopilotClientOptions cloned = original.clone(); - // Mutate the original environment map to test independence + // Mutate the source map after set — should not affect original or clone env.put("KEY2", "value2"); - // The cloned config should be unaffected by mutations to the original map + assertEquals(1, original.getEnvironment().size()); assertEquals(1, cloned.getEnvironment().size()); - assertEquals(2, original.getEnvironment().size()); + + // getEnvironment() returns a copy, so mutating it should not affect internals + original.getEnvironment().put("KEY3", "value3"); + assertEquals(1, original.getEnvironment().size()); } @Test From 49d56f3ca3205c4154040688d8eccd148269e5e3 Mon Sep 17 00:00:00 2001 From: edburns <75821+edburns@users.noreply.github.com> Date: Tue, 31 Mar 2026 18:55:26 +0000 Subject: [PATCH 25/80] Update JaCoCo coverage badge --- .github/badges/jacoco.svg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/badges/jacoco.svg b/.github/badges/jacoco.svg index 19da90d2e..482adb13b 100644 --- a/.github/badges/jacoco.svg +++ b/.github/badges/jacoco.svg @@ -12,7 +12,7 @@ coverage coverage - 85% - 85% + 84.7% + 84.7% From f8e59c8addcf72cce26dd6e0ae74198b707b5c8d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 31 Mar 2026 19:02:43 +0000 Subject: [PATCH 26/80] Initial plan From afc34c439dd3e393840fe3c213ccc4d7b12fed39 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Tue, 31 Mar 2026 16:09:48 -0400 Subject: [PATCH 27/80] Revert "Update .github/workflows/copilot-setup-steps.yml" This reverts commit dc71acbd18e0da9816c5f548c802213456e90b63. --- .github/workflows/copilot-setup-steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 145629457..8d8aa75c9 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -41,7 +41,7 @@ jobs: distribution: 'temurin' cache: 'maven' - # Enable repository pre-commit hooks (including Spotless checks for relevant source changes) + # Enable pre-commit hooks so Spotless formatting is enforced on every commit - name: Enable pre-commit hooks run: git config core.hooksPath .githooks From 05d06d97f398a092897725a7651af10f96a047da Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Tue, 31 Mar 2026 16:09:52 -0400 Subject: [PATCH 28/80] Revert "On branch edburns/spotless-agentic-workflow-42" This reverts commit 2ba6e1dc1083fd5fade553fcf515a0d17aeba349. --- .github/copilot-instructions.md | 12 ------------ .github/workflows/copilot-setup-steps.yml | 6 ------ 2 files changed, 18 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index e3a8eb275..d7dafb081 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -244,18 +244,6 @@ This SDK is designed to be **lightweight with minimal dependencies**: 5. Check for security vulnerabilities 6. Get team approval for non-trivial additions -## Pre-commit Hooks and Formatting (Coding Agent) - -The repository has a pre-commit hook (`.githooks/pre-commit`) that is **automatically enabled** in the Copilot coding agent environment via `copilot-setup-steps.yml`. The hook runs `mvn spotless:check` on any commit that includes changes under `src/`. - -**If a commit fails due to the pre-commit hook:** - -1. Run `mvn spotless:apply` to auto-fix formatting issues. -2. Re-stage the changed files with `git add -u`. -3. Retry the commit. - -**Best practice:** Always run `mvn spotless:apply` before committing Java source changes to avoid hook failures in the first place. If you forget and the hook rejects the commit, follow the three steps above and continue. - ## Commit and PR Guidelines ### Commit Messages diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 8d8aa75c9..6a0cdec5b 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -41,10 +41,6 @@ jobs: distribution: 'temurin' cache: 'maven' - # Enable pre-commit hooks so Spotless formatting is enforced on every commit - - name: Enable pre-commit hooks - run: git config core.hooksPath .githooks - # Verify installations - name: Verify tool installations run: | @@ -54,6 +50,4 @@ jobs: java -version gh --version gh aw version - echo "--- Git hooks path ---" - git config core.hooksPath echo "✅ All tools installed successfully" From 9b14893d92b70061e77aa5b59b07f93d22f9dcdb Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Tue, 31 Mar 2026 16:16:28 -0400 Subject: [PATCH 29/80] Add JDK 25 smoke test job with virtual thread support - Rename existing smoke-test job to smoke-test-jdk17 - Add smoke-test-java25 job using Microsoft JDK 25 - JDK 25 job instructs agent to follow // JDK 25+: marker comments in README Quick Start to enable virtual threads Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/run-smoke-test.yml | 56 +++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-smoke-test.yml b/.github/workflows/run-smoke-test.yml index d5181e038..8d0feac0c 100644 --- a/.github/workflows/run-smoke-test.yml +++ b/.github/workflows/run-smoke-test.yml @@ -11,8 +11,8 @@ permissions: contents: read jobs: - smoke-test: - name: Build SDK and run smoke test + smoke-test-jdk17: + name: Build SDK and run smoke test (JDK 17) runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' steps: @@ -59,3 +59,55 @@ jobs: cd smoke-test java -jar ./target/copilot-sdk-smoketest-1.0-SNAPSHOT.jar echo "Smoke test passed (exit code 0)" + + smoke-test-java25: + name: Build SDK and run smoke test (JDK 25) + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Set up JDK 25 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 + with: + java-version: "25" + distribution: "microsoft" + cache: "maven" + + - uses: ./.github/actions/setup-copilot + + - name: Build SDK and install to local repo + run: mvn -DskipTests -Pskip-test-harness clean install + + - name: Create and run smoke test via Copilot CLI + env: + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + run: | + cat > /tmp/smoke-test-prompt.txt << 'PROMPT_EOF' + You are running inside the copilot-sdk-java repository. + The SDK has already been built and installed into the local Maven repository. + JDK 25 and Maven are already installed and on PATH. + + Execute the prompt at `src/test/prompts/PROMPT-smoke-test.md` with the following critical overrides: + + **Critical override — disable SNAPSHOT updates (but allow downloads):** The goal of this workflow is to validate the SDK SNAPSHOT that was just built and installed locally, not any newer SNAPSHOT that might exist in a remote repository. To ensure Maven does not download a newer timestamped SNAPSHOT of the SDK while still allowing it to download any missing plugins or dependencies, you must run the smoke-test Maven build without `-U` and with `--no-snapshot-updates`, so that it uses the locally installed SDK artifact. Use `mvn --no-snapshot-updates clean package` instead of `mvn -U clean package` or `mvn -o clean package`. + + **Critical override — do NOT run the jar:** Stop after the `mvn --no-snapshot-updates clean package` build succeeds. Do NOT execute Step 4 (java -jar) or Step 5 (verify exit code) from the prompt. The workflow will run the jar in a separate deterministic step to guarantee the exit code propagates correctly. + + **Critical override — enable Virtual Threads for JDK 25:** After creating the Java source file from the README "Quick Start" section but BEFORE building, you must modify the source file to enable virtual thread support. The Quick Start code contains inline comments that start with `// JDK 25+:` — these are instructions. Find every such comment and follow what it says (comment out lines it says to comment out, uncomment lines it says to uncomment). Add any imports required by the newly uncommented code (e.g. `java.util.concurrent.Executors`). + Also set `maven.compiler.source` and `maven.compiler.target` to `25` in the `pom.xml`. + + Follow steps 1-3 only: create the `smoke-test/` directory, create `pom.xml` and the Java source file exactly as specified, apply the JDK 25 virtual thread modifications described above, and build with `mvn --no-snapshot-updates clean package` (no SNAPSHOT updates and without `-U`). + + If any step fails, exit with a non-zero exit code. Do not silently fix errors. + PROMPT_EOF + + copilot --yolo --prompt "$(cat /tmp/smoke-test-prompt.txt)" + + - name: Run smoke test jar + env: + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + run: | + cd smoke-test + java -jar ./target/copilot-sdk-smoketest-1.0-SNAPSHOT.jar + echo "Smoke test passed (exit code 0)" From 2108ece372154f02c47a5c40af15b2d18ead2648 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Thu, 2 Apr 2026 12:06:09 -0400 Subject: [PATCH 30/80] On branch main Prepare to release 0.2.1-java.1 modified: pom.xml --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index eee587375..c83d7ff9b 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.github copilot-sdk-java - 0.2.2-java.0-SNAPSHOT + 0.2.1-java.1-SNAPSHOT jar GitHub Copilot SDK :: Java From 8c2071597bf769b635790388fcea6e977d6b2302 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Thu, 2 Apr 2026 12:15:27 -0400 Subject: [PATCH 31/80] On branch main Document JDK 25 recommended level. 17 is still minimum. modified: README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 84f0d6d81..c081349cf 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,8 @@ Java SDK for programmatic control of GitHub Copilot CLI, enabling you to build A ### Requirements -- Java 17 or later -- GitHub Copilot CLI 0.0.411-1 or later installed and in PATH (or provide custom `cliPath`) +- Java 17 or later. **JDK 25 recommended**. Selecting JDK 25 enables the use of virtual threads, as shown in the [Quick Start](#quick-start). +- GitHub Copilot 1.0.15-0 or later installed and in `PATH` (or provide custom `cliPath`) ### Maven From 3ca5671f0cc4b336195ca97321478136d39f408a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 2 Apr 2026 16:21:22 +0000 Subject: [PATCH 32/80] docs: update version references to 0.2.1-java.1 --- CHANGELOG.md | 14 +++++++++++--- README.md | 4 ++-- src/site/markdown/cookbook/error-handling.md | 14 +++++++------- src/site/markdown/cookbook/managing-local-files.md | 4 ++-- src/site/markdown/cookbook/multiple-sessions.md | 4 ++-- src/site/markdown/cookbook/persisting-sessions.md | 6 +++--- src/site/markdown/cookbook/pr-visualization.md | 2 +- 7 files changed, 28 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c54038b9c..e306db097 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). > **Upstream sync:** [`github/copilot-sdk@4088739`](https://github.com/github/copilot-sdk/commit/40887393a9e687dacc141a645799441b0313ff15) +## [0.2.1-java.1] - 2026-04-02 + +> **Upstream sync:** [`github/copilot-sdk@4088739`](https://github.com/github/copilot-sdk/commit/40887393a9e687dacc141a645799441b0313ff15) ## [0.2.1-java.0] - 2026-03-26 > **Upstream sync:** [`github/copilot-sdk@4088739`](https://github.com/github/copilot-sdk/commit/40887393a9e687dacc141a645799441b0313ff15) @@ -462,12 +465,17 @@ New types: `GetForegroundSessionResponse`, `SetForegroundSessionResponse` - Pre-commit hook for Spotless code formatting - Comprehensive API documentation -[Unreleased]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.0...HEAD +[Unreleased]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.1...HEAD +[0.2.1-java.1]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.0...v0.2.1-java.1 +[Unreleased]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.1...HEAD +[0.2.1-java.1]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.0...v0.2.1-java.1 [0.2.1-java.0]: https://github.com/github/copilot-sdk-java/compare/v0.1.32-java.0...v0.2.1-java.0 -[Unreleased]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.0...HEAD +[Unreleased]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.1...HEAD +[0.2.1-java.1]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.0...v0.2.1-java.1 [0.2.1-java.0]: https://github.com/github/copilot-sdk-java/compare/v0.1.32-java.0...v0.2.1-java.0 [0.1.32-java.0]: https://github.com/github/copilot-sdk-java/compare/v1.0.11...v0.1.32-java.0 -[Unreleased]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.0...HEAD +[Unreleased]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.1...HEAD +[0.2.1-java.1]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.0...v0.2.1-java.1 [0.2.1-java.0]: https://github.com/github/copilot-sdk-java/compare/v0.1.32-java.0...v0.2.1-java.0 [0.1.32-java.0]: https://github.com/github/copilot-sdk-java/compare/v1.0.11...v0.1.32-java.0 [1.0.11]: https://github.com/github/copilot-sdk-java/compare/v1.0.10...v1.0.11 diff --git a/README.md b/README.md index c081349cf..3010b6839 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Java SDK for programmatic control of GitHub Copilot CLI, enabling you to build A com.github copilot-sdk-java - 0.2.1-java.0 + 0.2.1-java.1 ``` @@ -60,7 +60,7 @@ Snapshot builds of the next development version are published to Maven Central S ### Gradle ```groovy -implementation 'com.github:copilot-sdk-java:0.2.1-java.0' +implementation 'com.github:copilot-sdk-java:0.2.1-java.1' ``` ## Quick Start diff --git a/src/site/markdown/cookbook/error-handling.md b/src/site/markdown/cookbook/error-handling.md index d085ecd91..5ee5ef2ca 100644 --- a/src/site/markdown/cookbook/error-handling.md +++ b/src/site/markdown/cookbook/error-handling.md @@ -30,7 +30,7 @@ jbang BasicErrorHandling.java **Code:** ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.0 +//DEPS com.github:copilot-sdk-java:0.2.1-java.1 import com.github.copilot.sdk.CopilotClient; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; @@ -64,7 +64,7 @@ public class BasicErrorHandling { ## Handling specific error types ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.0 +//DEPS com.github:copilot-sdk-java:0.2.1-java.1 import com.github.copilot.sdk.CopilotClient; import java.util.concurrent.ExecutionException; @@ -99,7 +99,7 @@ public class SpecificErrorHandling { ## Timeout handling ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.0 +//DEPS com.github:copilot-sdk-java:0.2.1-java.1 import com.github.copilot.sdk.CopilotSession; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; @@ -130,7 +130,7 @@ public class TimeoutHandling { ## Aborting a request ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.0 +//DEPS com.github:copilot-sdk-java:0.2.1-java.1 import com.github.copilot.sdk.CopilotSession; import com.github.copilot.sdk.json.MessageOptions; import java.util.concurrent.Executors; @@ -162,7 +162,7 @@ public class AbortRequest { ## Graceful shutdown ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.0 +//DEPS com.github:copilot-sdk-java:0.2.1-java.1 import com.github.copilot.sdk.CopilotClient; public class GracefulShutdown { @@ -192,7 +192,7 @@ public class GracefulShutdown { ## Try-with-resources pattern ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.0 +//DEPS com.github:copilot-sdk-java:0.2.1-java.1 import com.github.copilot.sdk.CopilotClient; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; @@ -224,7 +224,7 @@ public class TryWithResources { ## Handling tool errors ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.0 +//DEPS com.github:copilot-sdk-java:0.2.1-java.1 import com.github.copilot.sdk.CopilotClient; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; diff --git a/src/site/markdown/cookbook/managing-local-files.md b/src/site/markdown/cookbook/managing-local-files.md index 4c0622928..aa9ba23bc 100644 --- a/src/site/markdown/cookbook/managing-local-files.md +++ b/src/site/markdown/cookbook/managing-local-files.md @@ -34,7 +34,7 @@ jbang ManagingLocalFiles.java **Code:** ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.0 +//DEPS com.github:copilot-sdk-java:0.2.1-java.1 import com.github.copilot.sdk.CopilotClient; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.events.SessionIdleEvent; @@ -161,7 +161,7 @@ session.send(new MessageOptions().setPrompt(prompt)); ## Interactive file organization ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.0 +//DEPS com.github:copilot-sdk-java:0.2.1-java.1 import java.io.BufferedReader; import java.io.InputStreamReader; diff --git a/src/site/markdown/cookbook/multiple-sessions.md b/src/site/markdown/cookbook/multiple-sessions.md index 0121bfc4c..fe5c2f0d9 100644 --- a/src/site/markdown/cookbook/multiple-sessions.md +++ b/src/site/markdown/cookbook/multiple-sessions.md @@ -30,7 +30,7 @@ jbang MultipleSessions.java **Code:** ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.0 +//DEPS com.github:copilot-sdk-java:0.2.1-java.1 import com.github.copilot.sdk.CopilotClient; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; @@ -123,7 +123,7 @@ try { ## Managing session lifecycle with CompletableFuture ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.0 +//DEPS com.github:copilot-sdk-java:0.2.1-java.1 import java.util.concurrent.CompletableFuture; import java.util.List; diff --git a/src/site/markdown/cookbook/persisting-sessions.md b/src/site/markdown/cookbook/persisting-sessions.md index 213959ce6..e3fd11b13 100644 --- a/src/site/markdown/cookbook/persisting-sessions.md +++ b/src/site/markdown/cookbook/persisting-sessions.md @@ -30,7 +30,7 @@ jbang PersistingSessions.java **Code:** ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.0 +//DEPS com.github:copilot-sdk-java:0.2.1-java.1 import com.github.copilot.sdk.CopilotClient; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; @@ -127,7 +127,7 @@ public class DeleteSession { ## Getting session history ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.0 +//DEPS com.github:copilot-sdk-java:0.2.1-java.1 import com.github.copilot.sdk.CopilotClient; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.events.UserMessageEvent; @@ -162,7 +162,7 @@ public class SessionHistory { ## Complete example with session management ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.0 +//DEPS com.github:copilot-sdk-java:0.2.1-java.1 import java.util.Scanner; public class SessionManager { diff --git a/src/site/markdown/cookbook/pr-visualization.md b/src/site/markdown/cookbook/pr-visualization.md index 77b6631b8..dbd240a40 100644 --- a/src/site/markdown/cookbook/pr-visualization.md +++ b/src/site/markdown/cookbook/pr-visualization.md @@ -34,7 +34,7 @@ jbang PRVisualization.java github/copilot-sdk ## Full example: PRVisualization.java ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.0 +//DEPS com.github:copilot-sdk-java:0.2.1-java.1 import com.github.copilot.sdk.CopilotClient; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.events.ToolExecutionStartEvent; From 64dbfc0f9d23e2d3498057315980c0dca9faed2b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 2 Apr 2026 16:21:43 +0000 Subject: [PATCH 33/80] [maven-release-plugin] prepare release v0.2.1-java.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c83d7ff9b..43e1b436d 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.github copilot-sdk-java - 0.2.1-java.1-SNAPSHOT + 0.2.1-java.1 jar GitHub Copilot SDK :: Java @@ -33,7 +33,7 @@ scm:git:https://github.com/github/copilot-sdk-java.git scm:git:https://github.com/github/copilot-sdk-java.git https://github.com/github/copilot-sdk-java - HEAD + v0.2.1-java.1 From 828d30010eb72f48a3340e524d09356104f91cc8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 2 Apr 2026 16:21:45 +0000 Subject: [PATCH 34/80] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 43e1b436d..45404d99a 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.github copilot-sdk-java - 0.2.1-java.1 + 0.2.2-java.1-SNAPSHOT jar GitHub Copilot SDK :: Java @@ -33,7 +33,7 @@ scm:git:https://github.com/github/copilot-sdk-java.git scm:git:https://github.com/github/copilot-sdk-java.git https://github.com/github/copilot-sdk-java - v0.2.1-java.1 + HEAD From 3862fdd97a20a6e763efa7873ce426ae45bc4bf4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 18:29:22 +0000 Subject: [PATCH 35/80] Initial plan From be757e1421924626969ca7dc4df9bd9796aae923 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 18:36:18 +0000 Subject: [PATCH 36/80] Fix weekly upstream sync agentic workflow prompt Rewrite the prompt from documentation-style to clear imperative instructions. The agent previously misinterpreted the documentation as instructions to perform the merge itself (invoking the agentic-merge-upstream skill), then failed because it couldn't push code from the sandbox. The new prompt: - Gives explicit step-by-step instructions - Provides bash commands for upstream change detection - Directs the agent to use safe-output tools (create_issue, close_issue, assign_to_agent, noop) - Explicitly prohibits invoking skills, editing files, or pushing code Only the markdown content changed; frontmatter is unchanged so no lock file recompilation is needed. Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/945e9454-9363-45bc-b281-0fe3d6c87019 Co-authored-by: brunoborges <129743+brunoborges@users.noreply.github.com> --- .github/workflows/weekly-upstream-sync.md | 134 ++++++++-------------- 1 file changed, 50 insertions(+), 84 deletions(-) diff --git a/.github/workflows/weekly-upstream-sync.md b/.github/workflows/weekly-upstream-sync.md index 641f29301..0aaff8d1e 100644 --- a/.github/workflows/weekly-upstream-sync.md +++ b/.github/workflows/weekly-upstream-sync.md @@ -41,111 +41,77 @@ safe-outputs: noop: report-as-issue: false --- -# Weekly Upstream Sync Agentic Workflow -This document describes the `weekly-upstream-sync.yml` GitHub Actions workflow, which automates the detection of new changes in the official [Copilot SDK](https://github.com/github/copilot-sdk) and delegates the merge work to the Copilot coding agent. +# Weekly Upstream Sync -## Overview +You are an automation agent that detects new upstream changes and creates GitHub issues. You do **NOT** perform any code merges, edits, or pushes. Do **NOT** invoke any skills (especially `agentic-merge-upstream`). Your only job is to check for changes and use safe-output tools to create or close issues. -The workflow runs on a **weekly schedule** (every Monday at 10:00 UTC) and can also be triggered manually. It does **not** perform the actual merge — instead, it detects upstream changes and creates a GitHub issue assigned to `copilot`, instructing the agent to follow the [agentic-merge-upstream](../prompts/agentic-merge-upstream.prompt.md) prompt to port the changes. +## Instructions -The agent must also create the Pull Request with the label `upstream-sync`. This allows the workflow to track the merge progress and avoid creating duplicate issues if the agent is still working on a previous sync. +Follow these steps exactly: -## Trigger +### Step 1: Read `.lastmerge` -| Trigger | Schedule | -|---|---| -| `schedule` | Every Monday at 10:00 UTC (`0 10 * * 1`) | -| `workflow_dispatch` | Manual trigger from the Actions tab | +Read the file `.lastmerge` in the repository root. It contains the SHA of the last upstream commit that was merged into this Java SDK. -## Workflow Steps +### Step 2: Check for upstream changes -### 1. Checkout repository +Clone the upstream repository and compare commits: -Checks out the repo to read the `.lastmerge` file, which contains the SHA of the last upstream commit that was merged into the Java SDK. - -### 2. Check for upstream changes - -- Reads the last merged commit hash from `.lastmerge` -- Clones the upstream `github/copilot-sdk` repository -- Compares `.lastmerge` against upstream `HEAD` -- If they match: sets `has_changes=false` -- If they differ: counts new commits, generates a summary (up to 20 most recent), and sets outputs (`commit_count`, `upstream_head`, `last_merge`, `summary`) - -### 3. Close previous upstream-sync issues (when changes found) - -**Condition:** `has_changes == true` +```bash +LAST_MERGE=$(cat .lastmerge) +git clone --quiet https://github.com/github/copilot-sdk.git /tmp/gh-aw/agent/upstream +cd /tmp/gh-aw/agent/upstream +UPSTREAM_HEAD=$(git rev-parse HEAD) +``` -Before creating a new issue, closes any existing open issues with the `upstream-sync` label. This prevents stale issues from accumulating when previous sync attempts were incomplete or superseded. Each closed issue receives a comment explaining it was superseded. +If `LAST_MERGE` equals `UPSTREAM_HEAD`, there are **no new changes**. Go to Step 3a. -### 4. Close stale upstream-sync issues (when no changes found) +If they differ, count the new commits and generate a summary: -**Condition:** `has_changes == false` +```bash +COMMIT_COUNT=$(git rev-list --count "$LAST_MERGE".."$UPSTREAM_HEAD") +SUMMARY=$(git log --oneline "$LAST_MERGE".."$UPSTREAM_HEAD" | head -20) +``` -If the upstream is already up to date, closes any lingering open `upstream-sync` issues with a comment noting that no changes were detected. This handles the case where a previous issue was created but the changes were merged manually (updating `.lastmerge`) before the agent completed. +Go to Step 3b. -### 5. Create issue and assign to Copilot +### Step 3a: No changes detected -**Condition:** `has_changes == true` +1. Search for any open issues with the `upstream-sync` label using the GitHub MCP tools. +2. If there are open `upstream-sync` issues, close each one using the `close_issue` safe-output tool with a comment: "No new upstream changes detected. The Java SDK is up to date. Closing." +3. Call the `noop` safe-output tool with message: "No new upstream changes since last merge ()." +4. **Stop here.** Do not proceed further. -Creates a new GitHub issue with: +### Step 3b: Changes detected -- **Title:** `Upstream sync: N new commits (YYYY-MM-DD)` -- **Label:** `upstream-sync` -- **Assignee:** `copilot` -- **Body:** Contains commit count, commit range links, a summary of recent commits, and a link to the merge prompt +1. Search for any open issues with the `upstream-sync` label using the GitHub MCP tools. +2. Close each existing open `upstream-sync` issue using the `close_issue` safe-output tool with a comment: "Superseded by a newer upstream sync check." +3. Create a new issue using the `create_issue` safe-output tool with: + - **Title:** `Upstream sync: new commits ()` + - **Body:** Include the following information: + ``` + ## Automated Upstream Sync -The Copilot coding agent picks up the issue, creates a branch and PR, then follows the merge prompt to port the changes. + There are **** new commits in the [official Copilot SDK](https://github.com/github/copilot-sdk) since the last merge. -### 6. Summary + - **Last merged commit:** [``](https://github.com/github/copilot-sdk/commit/) + - **Upstream HEAD:** [``](https://github.com/github/copilot-sdk/commit/) -Writes a GitHub Actions step summary with: + ### Recent upstream commits -- Whether changes were detected -- Commit count and range -- Recent upstream commits -- Link to the created issue (if any) + ``` +

+ ``` -## Flow Diagram + ### Instructions -``` -┌─────────────────────┐ -│ Schedule / Manual │ -└──────────┬──────────┘ - │ - ▼ -┌─────────────────────┐ -│ Read .lastmerge │ -│ Clone upstream SDK │ -│ Compare commits │ -└──────────┬──────────┘ - │ - ┌─────┴─────┐ - │ │ - changes? no changes - │ │ - ▼ ▼ -┌──────────┐ ┌──────────────────┐ -│ Close old│ │ Close stale │ -│ issues │ │ issues │ -└────┬─────┘ └──────────────────┘ - │ - ▼ -┌──────────────────────────┐ -│ Create issue assigned to │ -│ copilot │ -└──────────────────────────┘ - │ - ▼ -┌──────────────────────────┐ -│ Agent follows prompt to │ -│ port changes → PR │ -└──────────────────────────┘ -``` + Follow the [agentic-merge-upstream](.github/prompts/agentic-merge-upstream.prompt.md) prompt to port these changes to the Java SDK. + ``` +4. After creating the issue, use the `assign_to_agent` safe-output tool to assign Copilot to the newly created issue. -## Related Files +## Important constraints -| File | Purpose | -|---|---| -| `.lastmerge` | Stores the SHA of the last merged upstream commit | -| [agentic-merge-upstream.prompt.md](../prompts/agentic-merge-upstream.prompt.md) | Detailed instructions the Copilot agent follows to port changes | -| `.github/scripts/upstream-sync/` | Helper scripts used by the merge prompt | +- **Do NOT edit any files**, create branches, or push code. +- **Do NOT invoke any skills** such as `agentic-merge-upstream` or `commit-as-pull-request`. +- **Do NOT attempt to merge or port upstream changes.** That is done by a separate agent that picks up the issue you create. +- You **MUST** call at least one safe-output tool (`create_issue`, `close_issue`, `noop`, etc.) before finishing. From 844f3cf399af5f45279ed2cd6b8110e84bfe7a7b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 10:24:14 +0000 Subject: [PATCH 37/80] Initial plan From cc84fab663d4809e3592ff21193bdd9cf8964cf0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 10:46:28 +0000 Subject: [PATCH 38/80] Port Commands, Elicitation, and Capabilities features from upstream Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/16d575c4-83f4-4d20-99d9-b48635b3791d Co-authored-by: edburns <75821+edburns@users.noreply.github.com> --- .../com/github/copilot/sdk/CopilotClient.java | 31 ++ .../github/copilot/sdk/CopilotSession.java | 373 ++++++++++++++++++ .../copilot/sdk/SessionRequestBuilder.java | 33 ++ .../sdk/events/AbstractSessionEvent.java | 4 +- .../sdk/events/CapabilitiesChangedEvent.java | 44 +++ .../sdk/events/CommandExecuteEvent.java | 43 ++ .../sdk/events/ElicitationRequestedEvent.java | 54 +++ .../sdk/events/PermissionRequestedEvent.java | 3 +- .../sdk/events/SessionEventParser.java | 3 + .../copilot/sdk/json/CommandContext.java | 74 ++++ .../copilot/sdk/json/CommandDefinition.java | 98 +++++ .../copilot/sdk/json/CommandHandler.java | 41 ++ .../sdk/json/CommandWireDefinition.java | 58 +++ .../sdk/json/CreateSessionRequest.java | 26 ++ .../sdk/json/CreateSessionResponse.java | 5 +- .../copilot/sdk/json/ElicitationContext.java | 112 ++++++ .../copilot/sdk/json/ElicitationHandler.java | 44 +++ .../copilot/sdk/json/ElicitationParams.java | 58 +++ .../copilot/sdk/json/ElicitationResult.java | 68 ++++ .../sdk/json/ElicitationResultAction.java | 33 ++ .../copilot/sdk/json/ElicitationSchema.java | 92 +++++ .../sdk/json/GetSessionMetadataResponse.java | 15 + .../github/copilot/sdk/json/InputOptions.java | 108 +++++ .../copilot/sdk/json/ResumeSessionConfig.java | 54 +++ .../sdk/json/ResumeSessionRequest.java | 26 ++ .../sdk/json/ResumeSessionResponse.java | 5 +- .../copilot/sdk/json/SessionCapabilities.java | 39 ++ .../copilot/sdk/json/SessionConfig.java | 54 +++ .../github/copilot/sdk/json/SessionUiApi.java | 85 ++++ .../sdk/json/SessionUiCapabilities.java | 37 ++ 30 files changed, 1715 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/github/copilot/sdk/events/CapabilitiesChangedEvent.java create mode 100644 src/main/java/com/github/copilot/sdk/events/CommandExecuteEvent.java create mode 100644 src/main/java/com/github/copilot/sdk/events/ElicitationRequestedEvent.java create mode 100644 src/main/java/com/github/copilot/sdk/json/CommandContext.java create mode 100644 src/main/java/com/github/copilot/sdk/json/CommandDefinition.java create mode 100644 src/main/java/com/github/copilot/sdk/json/CommandHandler.java create mode 100644 src/main/java/com/github/copilot/sdk/json/CommandWireDefinition.java create mode 100644 src/main/java/com/github/copilot/sdk/json/ElicitationContext.java create mode 100644 src/main/java/com/github/copilot/sdk/json/ElicitationHandler.java create mode 100644 src/main/java/com/github/copilot/sdk/json/ElicitationParams.java create mode 100644 src/main/java/com/github/copilot/sdk/json/ElicitationResult.java create mode 100644 src/main/java/com/github/copilot/sdk/json/ElicitationResultAction.java create mode 100644 src/main/java/com/github/copilot/sdk/json/ElicitationSchema.java create mode 100644 src/main/java/com/github/copilot/sdk/json/GetSessionMetadataResponse.java create mode 100644 src/main/java/com/github/copilot/sdk/json/InputOptions.java create mode 100644 src/main/java/com/github/copilot/sdk/json/SessionCapabilities.java create mode 100644 src/main/java/com/github/copilot/sdk/json/SessionUiApi.java create mode 100644 src/main/java/com/github/copilot/sdk/json/SessionUiCapabilities.java diff --git a/src/main/java/com/github/copilot/sdk/CopilotClient.java b/src/main/java/com/github/copilot/sdk/CopilotClient.java index e2790f6a3..f00e2fd11 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotClient.java +++ b/src/main/java/com/github/copilot/sdk/CopilotClient.java @@ -24,6 +24,7 @@ import com.github.copilot.sdk.json.DeleteSessionResponse; import com.github.copilot.sdk.json.GetAuthStatusResponse; import com.github.copilot.sdk.json.GetLastSessionIdResponse; +import com.github.copilot.sdk.json.GetSessionMetadataResponse; import com.github.copilot.sdk.json.GetModelsResponse; import com.github.copilot.sdk.json.GetStatusResponse; import com.github.copilot.sdk.json.ListSessionsResponse; @@ -374,6 +375,7 @@ public CompletableFuture createSession(SessionConfig config) { return connection.rpc.invoke("session.create", request, CreateSessionResponse.class).thenApply(response -> { session.setWorkspacePath(response.workspacePath()); + session.setCapabilities(response.capabilities()); // If the server returned a different sessionId (e.g. a v2 CLI that ignores // the client-supplied ID), re-key the sessions map. String returnedId = response.sessionId(); @@ -444,6 +446,7 @@ public CompletableFuture resumeSession(String sessionId, ResumeS return connection.rpc.invoke("session.resume", request, ResumeSessionResponse.class).thenApply(response -> { session.setWorkspacePath(response.workspacePath()); + session.setCapabilities(response.capabilities()); // If the server returned a different sessionId than what was requested, re-key. String returnedId = response.sessionId(); if (returnedId != null && !returnedId.equals(sessionId)) { @@ -657,6 +660,34 @@ public CompletableFuture> listSessions(SessionListFilter f }); } + /** + * Gets metadata for a specific session by ID. + *

+ * This provides an efficient O(1) lookup of a single session's metadata instead + * of listing all sessions. + * + *

Example Usage

+ * + *
{@code
+     * var metadata = client.getSessionMetadata("session-123").get();
+     * if (metadata != null) {
+     * 	System.out.println("Session started at: " + metadata.getStartTime());
+     * }
+     * }
+ * + * @param sessionId + * the ID of the session to look up + * @return a future that resolves with the {@link SessionMetadata}, or + * {@code null} if the session was not found + * @see SessionMetadata + * @since 1.0.0 + */ + public CompletableFuture getSessionMetadata(String sessionId) { + return ensureConnected().thenCompose(connection -> connection.rpc + .invoke("session.getMetadata", Map.of("sessionId", sessionId), GetSessionMetadataResponse.class) + .thenApply(GetSessionMetadataResponse::session)); + } + /** * Gets the ID of the session currently displayed in the TUI. *

diff --git a/src/main/java/com/github/copilot/sdk/CopilotSession.java b/src/main/java/com/github/copilot/sdk/CopilotSession.java index 844737fc2..768f0adaa 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotSession.java +++ b/src/main/java/com/github/copilot/sdk/CopilotSession.java @@ -31,14 +31,27 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.github.copilot.sdk.events.AbstractSessionEvent; import com.github.copilot.sdk.events.AssistantMessageEvent; +import com.github.copilot.sdk.events.CapabilitiesChangedEvent; +import com.github.copilot.sdk.events.CommandExecuteEvent; +import com.github.copilot.sdk.events.ElicitationRequestedEvent; import com.github.copilot.sdk.events.ExternalToolRequestedEvent; import com.github.copilot.sdk.events.PermissionRequestedEvent; import com.github.copilot.sdk.events.SessionErrorEvent; import com.github.copilot.sdk.events.SessionEventParser; import com.github.copilot.sdk.events.SessionIdleEvent; import com.github.copilot.sdk.json.AgentInfo; +import com.github.copilot.sdk.json.CommandContext; +import com.github.copilot.sdk.json.CommandDefinition; +import com.github.copilot.sdk.json.CommandHandler; +import com.github.copilot.sdk.json.ElicitationContext; +import com.github.copilot.sdk.json.ElicitationHandler; +import com.github.copilot.sdk.json.ElicitationParams; +import com.github.copilot.sdk.json.ElicitationResult; +import com.github.copilot.sdk.json.ElicitationResultAction; +import com.github.copilot.sdk.json.ElicitationSchema; import com.github.copilot.sdk.json.GetMessagesResponse; import com.github.copilot.sdk.json.HookInvocation; +import com.github.copilot.sdk.json.InputOptions; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.PermissionInvocation; @@ -49,9 +62,12 @@ import com.github.copilot.sdk.json.PreToolUseHookInput; import com.github.copilot.sdk.json.SendMessageRequest; import com.github.copilot.sdk.json.SendMessageResponse; +import com.github.copilot.sdk.json.SessionCapabilities; import com.github.copilot.sdk.json.SessionEndHookInput; import com.github.copilot.sdk.json.SessionHooks; import com.github.copilot.sdk.json.SessionStartHookInput; +import com.github.copilot.sdk.json.SessionUiApi; +import com.github.copilot.sdk.json.SessionUiCapabilities; import com.github.copilot.sdk.json.ToolDefinition; import com.github.copilot.sdk.json.ToolResultObject; import com.github.copilot.sdk.json.UserInputHandler; @@ -116,11 +132,15 @@ public final class CopilotSession implements AutoCloseable { */ private volatile String sessionId; private volatile String workspacePath; + private volatile SessionCapabilities capabilities = new SessionCapabilities(); + private final SessionUiApi ui; private final JsonRpcClient rpc; private final Set> eventHandlers = ConcurrentHashMap.newKeySet(); private final Map toolHandlers = new ConcurrentHashMap<>(); + private final Map commandHandlers = new ConcurrentHashMap<>(); private final AtomicReference permissionHandler = new AtomicReference<>(); private final AtomicReference userInputHandler = new AtomicReference<>(); + private final AtomicReference elicitationHandler = new AtomicReference<>(); private final AtomicReference hooksHandler = new AtomicReference<>(); private volatile EventErrorHandler eventErrorHandler; private volatile EventErrorPolicy eventErrorPolicy = EventErrorPolicy.PROPAGATE_AND_LOG_ERRORS; @@ -163,6 +183,7 @@ public final class CopilotSession implements AutoCloseable { this.sessionId = sessionId; this.rpc = rpc; this.workspacePath = workspacePath; + this.ui = new SessionUiApiImpl(); var executor = new ScheduledThreadPoolExecutor(1, r -> { var t = new Thread(r, "sendAndWait-timeout"); t.setDaemon(true); @@ -225,6 +246,30 @@ void setWorkspacePath(String workspacePath) { this.workspacePath = workspacePath; } + /** + * Gets the capabilities reported by the host for this session. + *

+ * Capabilities are populated from the session create/resume response and + * updated in real time via {@code capabilities.changed} events. + * + * @return the session capabilities (never {@code null}) + */ + public SessionCapabilities getCapabilities() { + return capabilities; + } + + /** + * Gets the UI API for eliciting information from the user during this session. + *

+ * All methods on this API throw {@link IllegalStateException} if the host does + * not report elicitation support via {@link #getCapabilities()}. + * + * @return the UI API + */ + public SessionUiApi getUi() { + return ui; + } + /** * Sets a custom error handler for exceptions thrown by event handlers. *

@@ -669,11 +714,49 @@ private void handleBroadcastEventAsync(AbstractSessionEvent event) { if (data == null || data.requestId() == null || data.permissionRequest() == null) { return; } + if (Boolean.TRUE.equals(data.resolvedByHook())) { + return; // Already resolved by a permissionRequest hook; no client action needed. + } PermissionHandler handler = permissionHandler.get(); if (handler == null) { return; // This client doesn't handle permissions; another client will } executePermissionAndRespondAsync(data.requestId(), data.permissionRequest(), handler); + } else if (event instanceof CommandExecuteEvent cmdEvent) { + var data = cmdEvent.getData(); + if (data == null || data.requestId() == null) { + return; + } + executeCommandAndRespondAsync(data.requestId(), data.commandName(), data.command(), data.args()); + } else if (event instanceof ElicitationRequestedEvent elicitEvent) { + var data = elicitEvent.getData(); + if (data == null || data.requestId() == null) { + return; + } + ElicitationHandler handler = elicitationHandler.get(); + if (handler != null) { + ElicitationSchema schema = null; + if (data.requestedSchema() != null) { + schema = new ElicitationSchema().setType(data.requestedSchema().type()) + .setProperties(data.requestedSchema().properties()) + .setRequired(data.requestedSchema().required()); + } + var context = new ElicitationContext().setSessionId(sessionId).setMessage(data.message()) + .setRequestedSchema(schema).setMode(data.mode()).setElicitationSource(data.elicitationSource()) + .setUrl(data.url()); + handleElicitationRequestAsync(context, data.requestId()); + } + } else if (event instanceof CapabilitiesChangedEvent capEvent) { + var data = capEvent.getData(); + if (data != null) { + var newCapabilities = new SessionCapabilities(); + if (data.ui() != null) { + newCapabilities.setUi(new SessionUiCapabilities().setElicitation(data.ui().elicitation())); + } else { + newCapabilities.setUi(capabilities.getUi()); + } + capabilities = newCapabilities; + } } } @@ -816,6 +899,250 @@ void registerTools(List tools) { } } + /** + * Executes a command handler and sends the result back via + * {@code session.commands.handlePendingCommand}. + */ + private void executeCommandAndRespondAsync(String requestId, String commandName, String command, String args) { + CommandHandler handler = commandHandlers.get(commandName); + Runnable task = () -> { + if (handler == null) { + try { + rpc.invoke("session.commands.handlePendingCommand", Map.of("sessionId", sessionId, "requestId", + requestId, "error", "Unknown command: " + commandName), Object.class); + } catch (Exception e) { + LOG.log(Level.WARNING, "Error sending command error for requestId=" + requestId, e); + } + return; + } + try { + var ctx = new CommandContext().setSessionId(sessionId).setCommand(command).setCommandName(commandName) + .setArgs(args); + handler.handle(ctx).thenRun(() -> { + try { + rpc.invoke("session.commands.handlePendingCommand", + Map.of("sessionId", sessionId, "requestId", requestId), Object.class); + } catch (Exception e) { + LOG.log(Level.WARNING, "Error sending command result for requestId=" + requestId, e); + } + }).exceptionally(ex -> { + try { + String msg = ex.getMessage() != null ? ex.getMessage() : ex.toString(); + rpc.invoke("session.commands.handlePendingCommand", + Map.of("sessionId", sessionId, "requestId", requestId, "error", msg), Object.class); + } catch (Exception e) { + LOG.log(Level.WARNING, "Error sending command error for requestId=" + requestId, e); + } + return null; + }); + } catch (Exception e) { + LOG.log(Level.WARNING, "Error executing command for requestId=" + requestId, e); + try { + String msg = e.getMessage() != null ? e.getMessage() : e.toString(); + rpc.invoke("session.commands.handlePendingCommand", + Map.of("sessionId", sessionId, "requestId", requestId, "error", msg), Object.class); + } catch (Exception sendEx) { + LOG.log(Level.WARNING, "Error sending command error for requestId=" + requestId, sendEx); + } + } + }; + try { + if (executor != null) { + CompletableFuture.runAsync(task, executor); + } else { + CompletableFuture.runAsync(task); + } + } catch (RejectedExecutionException e) { + LOG.log(Level.WARNING, "Executor rejected command task for requestId=" + requestId + "; running inline", e); + task.run(); + } + } + + /** + * Dispatches an elicitation request to the registered handler and responds via + * {@code session.ui.handlePendingElicitation}. Auto-cancels on handler errors. + */ + private void handleElicitationRequestAsync(ElicitationContext context, String requestId) { + ElicitationHandler handler = elicitationHandler.get(); + if (handler == null) { + return; + } + Runnable task = () -> { + try { + handler.handle(context).thenAccept(result -> { + try { + String actionStr = result.getAction() != null + ? result.getAction().getValue() + : ElicitationResultAction.CANCEL.getValue(); + Map resultMap = result.getContent() != null + ? Map.of("action", actionStr, "content", result.getContent()) + : Map.of("action", actionStr); + rpc.invoke("session.ui.handlePendingElicitation", + Map.of("sessionId", sessionId, "requestId", requestId, "result", resultMap), + Object.class); + } catch (Exception e) { + LOG.log(Level.WARNING, "Error sending elicitation result for requestId=" + requestId, e); + } + }).exceptionally(ex -> { + try { + rpc.invoke("session.ui.handlePendingElicitation", Map.of("sessionId", sessionId, "requestId", + requestId, "result", Map.of("action", ElicitationResultAction.CANCEL.getValue())), + Object.class); + } catch (Exception e) { + LOG.log(Level.WARNING, "Error sending elicitation cancel for requestId=" + requestId, e); + } + return null; + }); + } catch (Exception e) { + LOG.log(Level.WARNING, "Error executing elicitation handler for requestId=" + requestId, e); + try { + rpc.invoke( + "session.ui.handlePendingElicitation", Map.of("sessionId", sessionId, "requestId", + requestId, "result", Map.of("action", ElicitationResultAction.CANCEL.getValue())), + Object.class); + } catch (Exception sendEx) { + LOG.log(Level.WARNING, "Error sending elicitation cancel for requestId=" + requestId, sendEx); + } + } + }; + try { + if (executor != null) { + CompletableFuture.runAsync(task, executor); + } else { + CompletableFuture.runAsync(task); + } + } catch (RejectedExecutionException e) { + LOG.log(Level.WARNING, "Executor rejected elicitation task for requestId=" + requestId + "; running inline", + e); + task.run(); + } + } + + /** + * Throws if the host does not support elicitation. + */ + private void assertElicitation() { + SessionCapabilities caps = capabilities; + if (caps == null || caps.getUi() == null || !Boolean.TRUE.equals(caps.getUi().getElicitation())) { + throw new IllegalStateException("Elicitation is not supported by the host. " + + "Check session.getCapabilities().getUi()?.getElicitation() before calling UI methods."); + } + } + + /** + * Implements {@link SessionUiApi} backed by the session's RPC connection. + */ + private final class SessionUiApiImpl implements SessionUiApi { + + @Override + public CompletableFuture elicitation(ElicitationParams params) { + assertElicitation(); + var schema = new java.util.HashMap(); + schema.put("type", params.getRequestedSchema().getType()); + schema.put("properties", params.getRequestedSchema().getProperties()); + if (params.getRequestedSchema().getRequired() != null) { + schema.put("required", params.getRequestedSchema().getRequired()); + } + return rpc.invoke("session.ui.elicitation", + Map.of("sessionId", sessionId, "message", params.getMessage(), "requestedSchema", schema), + ElicitationRpcResponse.class).thenApply(resp -> { + var result = new ElicitationResult(); + if (resp.action() != null) { + for (ElicitationResultAction a : ElicitationResultAction.values()) { + if (a.getValue().equalsIgnoreCase(resp.action())) { + result.setAction(a); + break; + } + } + } + if (result.getAction() == null) { + result.setAction(ElicitationResultAction.CANCEL); + } + result.setContent(resp.content()); + return result; + }); + } + + @Override + public CompletableFuture confirm(String message) { + assertElicitation(); + var field = Map.of("type", "boolean", "default", (Object) true); + var schema = Map.of("type", (Object) "object", "properties", (Object) Map.of("confirmed", (Object) field), + "required", (Object) new String[]{"confirmed"}); + return rpc.invoke("session.ui.elicitation", + Map.of("sessionId", sessionId, "message", message, "requestedSchema", schema), + ElicitationRpcResponse.class).thenApply(resp -> { + if ("accept".equalsIgnoreCase(resp.action()) && resp.content() != null) { + Object val = resp.content().get("confirmed"); + if (val instanceof Boolean b) { + return b; + } + if (val instanceof com.fasterxml.jackson.databind.node.BooleanNode bn) { + return bn.booleanValue(); + } + if (val instanceof String s) { + return Boolean.parseBoolean(s); + } + } + return false; + }); + } + + @Override + public CompletableFuture select(String message, String[] options) { + assertElicitation(); + var field = Map.of("type", (Object) "string", "enum", (Object) options); + var schema = Map.of("type", (Object) "object", "properties", (Object) Map.of("selection", (Object) field), + "required", (Object) new String[]{"selection"}); + return rpc.invoke("session.ui.elicitation", + Map.of("sessionId", sessionId, "message", message, "requestedSchema", schema), + ElicitationRpcResponse.class).thenApply(resp -> { + if ("accept".equalsIgnoreCase(resp.action()) && resp.content() != null) { + Object val = resp.content().get("selection"); + return val != null ? val.toString() : null; + } + return null; + }); + } + + @Override + public CompletableFuture input(String message, InputOptions options) { + assertElicitation(); + var field = new java.util.LinkedHashMap(); + field.put("type", "string"); + if (options != null) { + if (options.getTitle() != null) + field.put("title", options.getTitle()); + if (options.getDescription() != null) + field.put("description", options.getDescription()); + if (options.getMinLength() != null) + field.put("minLength", options.getMinLength()); + if (options.getMaxLength() != null) + field.put("maxLength", options.getMaxLength()); + if (options.getFormat() != null) + field.put("format", options.getFormat()); + if (options.getDefaultValue() != null) + field.put("default", options.getDefaultValue()); + } + var schema = Map.of("type", (Object) "object", "properties", (Object) Map.of("value", (Object) field), + "required", (Object) new String[]{"value"}); + return rpc.invoke("session.ui.elicitation", + Map.of("sessionId", sessionId, "message", message, "requestedSchema", schema), + ElicitationRpcResponse.class).thenApply(resp -> { + if ("accept".equalsIgnoreCase(resp.action()) && resp.content() != null) { + Object val = resp.content().get("value"); + return val != null ? val.toString() : null; + } + return null; + }); + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + private record ElicitationRpcResponse(@JsonProperty("action") String action, + @JsonProperty("content") Map content) { + } + /** * Retrieves a registered tool by name. * @@ -888,6 +1215,50 @@ void registerUserInputHandler(UserInputHandler handler) { userInputHandler.set(handler); } + /** + * Registers command handlers for this session. + *

+ * Called internally when creating or resuming a session with commands. + * + * @param commands + * the command definitions to register + */ + void registerCommands(java.util.List commands) { + commandHandlers.clear(); + if (commands != null) { + for (CommandDefinition cmd : commands) { + if (cmd.getName() != null && cmd.getHandler() != null) { + commandHandlers.put(cmd.getName(), cmd.getHandler()); + } + } + } + } + + /** + * Registers an elicitation handler for this session. + *

+ * Called internally when creating or resuming a session with an elicitation + * handler. + * + * @param handler + * the handler to invoke when an elicitation request is received + */ + void registerElicitationHandler(ElicitationHandler handler) { + elicitationHandler.set(handler); + } + + /** + * Sets the capabilities reported by the host for this session. + *

+ * Called internally after session create/resume response. + * + * @param sessionCapabilities + * the capabilities to set, or {@code null} for empty capabilities + */ + void setCapabilities(SessionCapabilities sessionCapabilities) { + this.capabilities = sessionCapabilities != null ? sessionCapabilities : new SessionCapabilities(); + } + /** * Handles a user input request from the Copilot CLI. *

@@ -1366,8 +1737,10 @@ public void close() { eventHandlers.clear(); toolHandlers.clear(); + commandHandlers.clear(); permissionHandler.set(null); userInputHandler.set(null); + elicitationHandler.set(null); hooksHandler.set(null); } diff --git a/src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java b/src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java index 6f1cd573c..d74bbfaf3 100644 --- a/src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java +++ b/src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java @@ -10,6 +10,7 @@ import java.util.function.Function; import com.github.copilot.sdk.json.CreateSessionRequest; +import com.github.copilot.sdk.json.CommandWireDefinition; import com.github.copilot.sdk.json.ResumeSessionConfig; import com.github.copilot.sdk.json.ResumeSessionRequest; import com.github.copilot.sdk.json.SectionOverride; @@ -122,6 +123,16 @@ static CreateSessionRequest buildCreateRequest(SessionConfig config, String sess request.setDisabledSkills(config.getDisabledSkills()); request.setConfigDir(config.getConfigDir()); + if (config.getCommands() != null && !config.getCommands().isEmpty()) { + var wireCommands = config.getCommands().stream() + .map(c -> new CommandWireDefinition(c.getName(), c.getDescription())) + .collect(java.util.stream.Collectors.toList()); + request.setCommands(wireCommands); + } + if (config.getOnElicitationRequest() != null) { + request.setRequestElicitation(true); + } + return request; } @@ -183,6 +194,16 @@ static ResumeSessionRequest buildResumeRequest(String sessionId, ResumeSessionCo request.setDisabledSkills(config.getDisabledSkills()); request.setInfiniteSessions(config.getInfiniteSessions()); + if (config.getCommands() != null && !config.getCommands().isEmpty()) { + var wireCommands = config.getCommands().stream() + .map(c -> new CommandWireDefinition(c.getName(), c.getDescription())) + .collect(java.util.stream.Collectors.toList()); + request.setCommands(wireCommands); + } + if (config.getOnElicitationRequest() != null) { + request.setRequestElicitation(true); + } + return request; } @@ -211,6 +232,12 @@ static void configureSession(CopilotSession session, SessionConfig config) { if (config.getHooks() != null) { session.registerHooks(config.getHooks()); } + if (config.getCommands() != null) { + session.registerCommands(config.getCommands()); + } + if (config.getOnElicitationRequest() != null) { + session.registerElicitationHandler(config.getOnElicitationRequest()); + } if (config.getOnEvent() != null) { session.on(config.getOnEvent()); } @@ -241,6 +268,12 @@ static void configureSession(CopilotSession session, ResumeSessionConfig config) if (config.getHooks() != null) { session.registerHooks(config.getHooks()); } + if (config.getCommands() != null) { + session.registerCommands(config.getCommands()); + } + if (config.getOnElicitationRequest() != null) { + session.registerElicitationHandler(config.getOnElicitationRequest()); + } if (config.getOnEvent() != null) { session.on(config.getOnEvent()); } diff --git a/src/main/java/com/github/copilot/sdk/events/AbstractSessionEvent.java b/src/main/java/com/github/copilot/sdk/events/AbstractSessionEvent.java index 4626bb4f8..51f6d8712 100644 --- a/src/main/java/com/github/copilot/sdk/events/AbstractSessionEvent.java +++ b/src/main/java/com/github/copilot/sdk/events/AbstractSessionEvent.java @@ -65,8 +65,8 @@ public abstract sealed class AbstractSessionEvent permits ToolExecutionCompleteEvent, // Broadcast request/completion events (protocol v3) ExternalToolRequestedEvent, ExternalToolCompletedEvent, PermissionRequestedEvent, PermissionCompletedEvent, - CommandQueuedEvent, CommandCompletedEvent, ExitPlanModeRequestedEvent, ExitPlanModeCompletedEvent, - SystemNotificationEvent, + CommandQueuedEvent, CommandCompletedEvent, CommandExecuteEvent, ElicitationRequestedEvent, + CapabilitiesChangedEvent, ExitPlanModeRequestedEvent, ExitPlanModeCompletedEvent, SystemNotificationEvent, // User events UserMessageEvent, PendingMessagesModifiedEvent, // Skill events diff --git a/src/main/java/com/github/copilot/sdk/events/CapabilitiesChangedEvent.java b/src/main/java/com/github/copilot/sdk/events/CapabilitiesChangedEvent.java new file mode 100644 index 000000000..0db68189d --- /dev/null +++ b/src/main/java/com/github/copilot/sdk/events/CapabilitiesChangedEvent.java @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk.events; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Event: capabilities.changed + *

+ * Broadcast when the host's session capabilities change. The SDK updates + * {@link com.github.copilot.sdk.CopilotSession#getCapabilities()} accordingly. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public final class CapabilitiesChangedEvent extends AbstractSessionEvent { + + @JsonProperty("data") + private CapabilitiesChangedData data; + + @Override + public String getType() { + return "capabilities.changed"; + } + + public CapabilitiesChangedData getData() { + return data; + } + + public void setData(CapabilitiesChangedData data) { + this.data = data; + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public record CapabilitiesChangedData(@JsonProperty("ui") CapabilitiesChangedUi ui) { + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public record CapabilitiesChangedUi(@JsonProperty("elicitation") Boolean elicitation) { + } +} diff --git a/src/main/java/com/github/copilot/sdk/events/CommandExecuteEvent.java b/src/main/java/com/github/copilot/sdk/events/CommandExecuteEvent.java new file mode 100644 index 000000000..c08c4a88d --- /dev/null +++ b/src/main/java/com/github/copilot/sdk/events/CommandExecuteEvent.java @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk.events; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Event: command.execute + *

+ * Broadcast when the user executes a slash command registered by this client. + * Clients that have a matching command handler should respond via + * {@code session.commands.handlePendingCommand}. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public final class CommandExecuteEvent extends AbstractSessionEvent { + + @JsonProperty("data") + private CommandExecuteData data; + + @Override + public String getType() { + return "command.execute"; + } + + public CommandExecuteData getData() { + return data; + } + + public void setData(CommandExecuteData data) { + this.data = data; + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public record CommandExecuteData(@JsonProperty("requestId") String requestId, + @JsonProperty("command") String command, @JsonProperty("commandName") String commandName, + @JsonProperty("args") String args) { + } +} diff --git a/src/main/java/com/github/copilot/sdk/events/ElicitationRequestedEvent.java b/src/main/java/com/github/copilot/sdk/events/ElicitationRequestedEvent.java new file mode 100644 index 000000000..e459dfb77 --- /dev/null +++ b/src/main/java/com/github/copilot/sdk/events/ElicitationRequestedEvent.java @@ -0,0 +1,54 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk.events; + +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Event: elicitation.requested + *

+ * Broadcast when the server or an MCP tool requests structured input from the + * user. Clients that have an elicitation handler should respond via + * {@code session.ui.handlePendingElicitation}. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public final class ElicitationRequestedEvent extends AbstractSessionEvent { + + @JsonProperty("data") + private ElicitationRequestedData data; + + @Override + public String getType() { + return "elicitation.requested"; + } + + public ElicitationRequestedData getData() { + return data; + } + + public void setData(ElicitationRequestedData data) { + this.data = data; + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public record ElicitationRequestedData(@JsonProperty("requestId") String requestId, + @JsonProperty("toolCallId") String toolCallId, @JsonProperty("elicitationSource") String elicitationSource, + @JsonProperty("message") String message, @JsonProperty("mode") String mode, + @JsonProperty("requestedSchema") ElicitationRequestedSchema requestedSchema, + @JsonProperty("url") String url) { + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public record ElicitationRequestedSchema(@JsonProperty("type") String type, + @JsonProperty("properties") Map properties, + @JsonProperty("required") List required) { + } +} diff --git a/src/main/java/com/github/copilot/sdk/events/PermissionRequestedEvent.java b/src/main/java/com/github/copilot/sdk/events/PermissionRequestedEvent.java index d8f9ec147..7ebce5ac7 100644 --- a/src/main/java/com/github/copilot/sdk/events/PermissionRequestedEvent.java +++ b/src/main/java/com/github/copilot/sdk/events/PermissionRequestedEvent.java @@ -38,6 +38,7 @@ public void setData(PermissionRequestedData data) { @JsonIgnoreProperties(ignoreUnknown = true) public record PermissionRequestedData(@JsonProperty("requestId") String requestId, - @JsonProperty("permissionRequest") PermissionRequest permissionRequest) { + @JsonProperty("permissionRequest") PermissionRequest permissionRequest, + @JsonProperty("resolvedByHook") Boolean resolvedByHook) { } } diff --git a/src/main/java/com/github/copilot/sdk/events/SessionEventParser.java b/src/main/java/com/github/copilot/sdk/events/SessionEventParser.java index 308317e6b..dda971769 100644 --- a/src/main/java/com/github/copilot/sdk/events/SessionEventParser.java +++ b/src/main/java/com/github/copilot/sdk/events/SessionEventParser.java @@ -99,6 +99,9 @@ public class SessionEventParser { TYPE_MAP.put("permission.completed", PermissionCompletedEvent.class); TYPE_MAP.put("command.queued", CommandQueuedEvent.class); TYPE_MAP.put("command.completed", CommandCompletedEvent.class); + TYPE_MAP.put("command.execute", CommandExecuteEvent.class); + TYPE_MAP.put("elicitation.requested", ElicitationRequestedEvent.class); + TYPE_MAP.put("capabilities.changed", CapabilitiesChangedEvent.class); TYPE_MAP.put("exit_plan_mode.requested", ExitPlanModeRequestedEvent.class); TYPE_MAP.put("exit_plan_mode.completed", ExitPlanModeCompletedEvent.class); TYPE_MAP.put("system.notification", SystemNotificationEvent.class); diff --git a/src/main/java/com/github/copilot/sdk/json/CommandContext.java b/src/main/java/com/github/copilot/sdk/json/CommandContext.java new file mode 100644 index 000000000..4657699bb --- /dev/null +++ b/src/main/java/com/github/copilot/sdk/json/CommandContext.java @@ -0,0 +1,74 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk.json; + +/** + * Context passed to a {@link CommandHandler} when a slash command is executed. + * + * @since 1.0.0 + */ +public class CommandContext { + + private String sessionId; + private String command; + private String commandName; + private String args; + + /** Gets the session ID where the command was invoked. @return the session ID */ + public String getSessionId() { + return sessionId; + } + + /** Sets the session ID. @param sessionId the session ID @return this */ + public CommandContext setSessionId(String sessionId) { + this.sessionId = sessionId; + return this; + } + + /** + * Gets the full command text (e.g., {@code /deploy production}). + * + * @return the full command text + */ + public String getCommand() { + return command; + } + + /** Sets the full command text. @param command the command text @return this */ + public CommandContext setCommand(String command) { + this.command = command; + return this; + } + + /** + * Gets the command name without the leading {@code /}. + * + * @return the command name + */ + public String getCommandName() { + return commandName; + } + + /** Sets the command name. @param commandName the command name @return this */ + public CommandContext setCommandName(String commandName) { + this.commandName = commandName; + return this; + } + + /** + * Gets the raw argument string after the command name. + * + * @return the argument string + */ + public String getArgs() { + return args; + } + + /** Sets the argument string. @param args the argument string @return this */ + public CommandContext setArgs(String args) { + this.args = args; + return this; + } +} diff --git a/src/main/java/com/github/copilot/sdk/json/CommandDefinition.java b/src/main/java/com/github/copilot/sdk/json/CommandDefinition.java new file mode 100644 index 000000000..33a6cbada --- /dev/null +++ b/src/main/java/com/github/copilot/sdk/json/CommandDefinition.java @@ -0,0 +1,98 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk.json; + +/** + * Defines a slash command that users can invoke from the CLI TUI. + *

+ * Register commands via {@link SessionConfig#setCommands(java.util.List)} or + * {@link ResumeSessionConfig#setCommands(java.util.List)}. Each command appears + * as {@code /name} in the CLI TUI. + * + *

Example Usage

+ * + *
{@code
+ * var config = new SessionConfig().setCommands(List.of(
+ * 		new CommandDefinition().setName("deploy").setDescription("Deploy the application").setHandler(context -> {
+ * 			System.out.println("Deploying: " + context.getArgs());
+ * 			return CompletableFuture.completedFuture(null);
+ * 		})));
+ * }
+ * + * @see CommandHandler + * @see CommandContext + * @since 1.0.0 + */ +public class CommandDefinition { + + private String name; + private String description; + private CommandHandler handler; + + /** + * Gets the command name (without leading {@code /}). + * + * @return the command name + */ + public String getName() { + return name; + } + + /** + * Sets the command name (without leading {@code /}). + *

+ * For example, {@code "deploy"} registers the {@code /deploy} command. + * + * @param name + * the command name + * @return this instance for method chaining + */ + public CommandDefinition setName(String name) { + this.name = name; + return this; + } + + /** + * Gets the human-readable description shown in the command completion UI. + * + * @return the description, or {@code null} if not set + */ + public String getDescription() { + return description; + } + + /** + * Sets the human-readable description shown in the command completion UI. + * + * @param description + * the description + * @return this instance for method chaining + */ + public CommandDefinition setDescription(String description) { + this.description = description; + return this; + } + + /** + * Gets the handler invoked when the command is executed. + * + * @return the command handler + */ + public CommandHandler getHandler() { + return handler; + } + + /** + * Sets the handler invoked when the command is executed. + * + * @param handler + * the command handler + * @return this instance for method chaining + */ + public CommandDefinition setHandler(CommandHandler handler) { + this.handler = handler; + return this; + } +} diff --git a/src/main/java/com/github/copilot/sdk/json/CommandHandler.java b/src/main/java/com/github/copilot/sdk/json/CommandHandler.java new file mode 100644 index 000000000..d63955638 --- /dev/null +++ b/src/main/java/com/github/copilot/sdk/json/CommandHandler.java @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk.json; + +import java.util.concurrent.CompletableFuture; + +/** + * Functional interface for handling slash-command executions. + *

+ * Implement this interface to define the behavior of a registered slash + * command. The handler is invoked when the user executes the command in the CLI + * TUI. + * + *

Example Usage

+ * + *
{@code
+ * CommandHandler deployHandler = context -> {
+ * 	System.out.println("Deploying with args: " + context.getArgs());
+ * 	// perform deployment...
+ * 	return CompletableFuture.completedFuture(null);
+ * };
+ * }
+ * + * @see CommandDefinition + * @since 1.0.0 + */ +@FunctionalInterface +public interface CommandHandler { + + /** + * Handles a slash-command execution. + * + * @param context + * the command context containing session ID, command text, and + * arguments + * @return a future that completes when the command handling is done + */ + CompletableFuture handle(CommandContext context); +} diff --git a/src/main/java/com/github/copilot/sdk/json/CommandWireDefinition.java b/src/main/java/com/github/copilot/sdk/json/CommandWireDefinition.java new file mode 100644 index 000000000..2ee65c58e --- /dev/null +++ b/src/main/java/com/github/copilot/sdk/json/CommandWireDefinition.java @@ -0,0 +1,58 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk.json; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Wire-format representation of a command definition for RPC serialization. + *

+ * This is a low-level class used internally. Use {@link CommandDefinition} to + * define commands for a session. + * + * @since 1.0.0 + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public final class CommandWireDefinition { + + @JsonProperty("name") + private String name; + + @JsonProperty("description") + private String description; + + /** Creates an empty definition. */ + public CommandWireDefinition() { + } + + /** Creates a definition with name and description. */ + public CommandWireDefinition(String name, String description) { + this.name = name; + this.description = description; + } + + /** Gets the command name. @return the name */ + public String getName() { + return name; + } + + /** Sets the command name. @param name the name @return this */ + public CommandWireDefinition setName(String name) { + this.name = name; + return this; + } + + /** Gets the description. @return the description */ + public String getDescription() { + return description; + } + + /** Sets the description. @param description the description @return this */ + public CommandWireDefinition setDescription(String description) { + this.description = description; + return this; + } +} 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 c0243f14b..d030631de 100644 --- a/src/main/java/com/github/copilot/sdk/json/CreateSessionRequest.java +++ b/src/main/java/com/github/copilot/sdk/json/CreateSessionRequest.java @@ -91,6 +91,12 @@ public final class CreateSessionRequest { @JsonProperty("configDir") private String configDir; + @JsonProperty("commands") + private List commands; + + @JsonProperty("requestElicitation") + private Boolean requestElicitation; + /** Gets the model name. @return the model */ public String getModel() { return model; @@ -312,4 +318,24 @@ public String getConfigDir() { public void setConfigDir(String configDir) { this.configDir = configDir; } + + /** Gets the commands wire definitions. @return the commands */ + public List getCommands() { + return commands == null ? null : Collections.unmodifiableList(commands); + } + + /** Sets the commands wire definitions. @param commands the commands */ + public void setCommands(List commands) { + this.commands = commands; + } + + /** Gets the requestElicitation flag. @return the flag */ + public Boolean getRequestElicitation() { + return requestElicitation; + } + + /** Sets the requestElicitation flag. @param requestElicitation the flag */ + public void setRequestElicitation(Boolean requestElicitation) { + this.requestElicitation = requestElicitation; + } } diff --git a/src/main/java/com/github/copilot/sdk/json/CreateSessionResponse.java b/src/main/java/com/github/copilot/sdk/json/CreateSessionResponse.java index 5b1a177f0..b47af050b 100644 --- a/src/main/java/com/github/copilot/sdk/json/CreateSessionResponse.java +++ b/src/main/java/com/github/copilot/sdk/json/CreateSessionResponse.java @@ -11,9 +11,12 @@ * @param workspacePath * the workspace path, or {@code null} if infinite sessions are * disabled + * @param capabilities + * the capabilities reported by the host, or {@code null} * @since 1.0.0 */ @JsonInclude(JsonInclude.Include.NON_NULL) public record CreateSessionResponse(@JsonProperty("sessionId") String sessionId, - @JsonProperty("workspacePath") String workspacePath) { + @JsonProperty("workspacePath") String workspacePath, + @JsonProperty("capabilities") SessionCapabilities capabilities) { } diff --git a/src/main/java/com/github/copilot/sdk/json/ElicitationContext.java b/src/main/java/com/github/copilot/sdk/json/ElicitationContext.java new file mode 100644 index 000000000..87687b194 --- /dev/null +++ b/src/main/java/com/github/copilot/sdk/json/ElicitationContext.java @@ -0,0 +1,112 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk.json; + +/** + * Context for an elicitation request received from the server or MCP tools. + * + * @since 1.0.0 + */ +public class ElicitationContext { + + private String sessionId; + private String message; + private ElicitationSchema requestedSchema; + private String mode; + private String elicitationSource; + private String url; + + /** + * Gets the session ID that triggered the elicitation request. @return the + * session ID + */ + public String getSessionId() { + return sessionId; + } + + /** Sets the session ID. @param sessionId the session ID @return this */ + public ElicitationContext setSessionId(String sessionId) { + this.sessionId = sessionId; + return this; + } + + /** + * Gets the message describing what information is needed from the user. + * + * @return the message + */ + public String getMessage() { + return message; + } + + /** Sets the message. @param message the message @return this */ + public ElicitationContext setMessage(String message) { + this.message = message; + return this; + } + + /** + * Gets the JSON Schema describing the form fields to present (form mode only). + * + * @return the schema, or {@code null} + */ + public ElicitationSchema getRequestedSchema() { + return requestedSchema; + } + + /** Sets the schema. @param requestedSchema the schema @return this */ + public ElicitationContext setRequestedSchema(ElicitationSchema requestedSchema) { + this.requestedSchema = requestedSchema; + return this; + } + + /** + * Gets the elicitation mode: {@code "form"} for structured input, {@code "url"} + * for browser redirect. + * + * @return the mode, or {@code null} (defaults to {@code "form"}) + */ + public String getMode() { + return mode; + } + + /** Sets the mode. @param mode the mode @return this */ + public ElicitationContext setMode(String mode) { + this.mode = mode; + return this; + } + + /** + * Gets the source that initiated the request (e.g., MCP server name). + * + * @return the elicitation source, or {@code null} + */ + public String getElicitationSource() { + return elicitationSource; + } + + /** + * Sets the elicitation source. @param elicitationSource the source @return this + */ + public ElicitationContext setElicitationSource(String elicitationSource) { + this.elicitationSource = elicitationSource; + return this; + } + + /** + * Gets the URL to open in the user's browser (url mode only). + * + * @return the URL, or {@code null} + */ + public String getUrl() { + return url; + } + + /** Sets the URL. @param url the URL @return this */ + public ElicitationContext setUrl(String url) { + this.url = url; + return this; + } +} diff --git a/src/main/java/com/github/copilot/sdk/json/ElicitationHandler.java b/src/main/java/com/github/copilot/sdk/json/ElicitationHandler.java new file mode 100644 index 000000000..d0a0d0616 --- /dev/null +++ b/src/main/java/com/github/copilot/sdk/json/ElicitationHandler.java @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk.json; + +import java.util.concurrent.CompletableFuture; + +/** + * Functional interface for handling elicitation requests from the server. + *

+ * Register an elicitation handler via + * {@link SessionConfig#setOnElicitationRequest(ElicitationHandler)} or + * {@link ResumeSessionConfig#setOnElicitationRequest(ElicitationHandler)}. When + * provided, the server routes elicitation requests to this handler and reports + * elicitation as a supported capability. + * + *

Example Usage

+ * + *
{@code
+ * ElicitationHandler handler = context -> {
+ * 	// Show the form to the user and collect responses
+ * 	Map formValues = showForm(context.getMessage(), context.getRequestedSchema());
+ * 	return CompletableFuture.completedFuture(
+ * 			new ElicitationResult().setAction(ElicitationResultAction.ACCEPT).setContent(formValues));
+ * };
+ * }
+ * + * @see ElicitationContext + * @see ElicitationResult + * @since 1.0.0 + */ +@FunctionalInterface +public interface ElicitationHandler { + + /** + * Handles an elicitation request from the server. + * + * @param context + * the elicitation context containing the message, schema, and mode + * @return a future that resolves with the elicitation result + */ + CompletableFuture handle(ElicitationContext context); +} diff --git a/src/main/java/com/github/copilot/sdk/json/ElicitationParams.java b/src/main/java/com/github/copilot/sdk/json/ElicitationParams.java new file mode 100644 index 000000000..8bd81022e --- /dev/null +++ b/src/main/java/com/github/copilot/sdk/json/ElicitationParams.java @@ -0,0 +1,58 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk.json; + +/** + * Parameters for an elicitation request sent from the SDK to the host. + * + * @since 1.0.0 + */ +public class ElicitationParams { + + private String message; + private ElicitationSchema requestedSchema; + + /** + * Gets the message describing what information is needed from the user. + * + * @return the message + */ + public String getMessage() { + return message; + } + + /** + * Sets the message describing what information is needed from the user. + * + * @param message + * the message + * @return this instance for method chaining + */ + public ElicitationParams setMessage(String message) { + this.message = message; + return this; + } + + /** + * Gets the JSON Schema describing the form fields to present. + * + * @return the requested schema + */ + public ElicitationSchema getRequestedSchema() { + return requestedSchema; + } + + /** + * Sets the JSON Schema describing the form fields to present. + * + * @param requestedSchema + * the schema + * @return this instance for method chaining + */ + public ElicitationParams setRequestedSchema(ElicitationSchema requestedSchema) { + this.requestedSchema = requestedSchema; + return this; + } +} diff --git a/src/main/java/com/github/copilot/sdk/json/ElicitationResult.java b/src/main/java/com/github/copilot/sdk/json/ElicitationResult.java new file mode 100644 index 000000000..3ba30b83d --- /dev/null +++ b/src/main/java/com/github/copilot/sdk/json/ElicitationResult.java @@ -0,0 +1,68 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk.json; + +import java.util.Map; + +/** + * Result returned from an elicitation dialog. + * + * @since 1.0.0 + */ +public class ElicitationResult { + + private ElicitationResultAction action; + private Map content; + + /** + * Gets the user action taken on the elicitation dialog. + *

+ * {@link ElicitationResultAction#ACCEPT} means the user submitted the form, + * {@link ElicitationResultAction#DECLINE} means the user rejected the request, + * and {@link ElicitationResultAction#CANCEL} means the user dismissed the + * dialog. + * + * @return the user action + */ + public ElicitationResultAction getAction() { + return action; + } + + /** + * Sets the user action taken on the elicitation dialog. + * + * @param action + * the user action + * @return this instance for method chaining + */ + public ElicitationResult setAction(ElicitationResultAction action) { + this.action = action; + return this; + } + + /** + * Gets the form values submitted by the user. + *

+ * Only present when {@link #getAction()} is + * {@link ElicitationResultAction#ACCEPT}. + * + * @return the submitted form values, or {@code null} if the user did not accept + */ + public Map getContent() { + return content; + } + + /** + * Sets the form values submitted by the user. + * + * @param content + * the submitted form values + * @return this instance for method chaining + */ + public ElicitationResult setContent(Map content) { + this.content = content; + return this; + } +} diff --git a/src/main/java/com/github/copilot/sdk/json/ElicitationResultAction.java b/src/main/java/com/github/copilot/sdk/json/ElicitationResultAction.java new file mode 100644 index 000000000..fd280cdeb --- /dev/null +++ b/src/main/java/com/github/copilot/sdk/json/ElicitationResultAction.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk.json; + +/** + * Action value for an {@link ElicitationResult}. + * + * @since 1.0.0 + */ +public enum ElicitationResultAction { + + /** The user submitted the form (accepted). */ + ACCEPT("accept"), + + /** The user explicitly rejected the request. */ + DECLINE("decline"), + + /** The user dismissed the dialog without responding. */ + CANCEL("cancel"); + + private final String value; + + ElicitationResultAction(String value) { + this.value = value; + } + + /** Returns the wire-format string value. @return the string value */ + public String getValue() { + return value; + } +} diff --git a/src/main/java/com/github/copilot/sdk/json/ElicitationSchema.java b/src/main/java/com/github/copilot/sdk/json/ElicitationSchema.java new file mode 100644 index 000000000..c3d548775 --- /dev/null +++ b/src/main/java/com/github/copilot/sdk/json/ElicitationSchema.java @@ -0,0 +1,92 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk.json; + +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * JSON Schema describing the form fields to present for an elicitation dialog. + * + * @since 1.0.0 + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ElicitationSchema { + + @JsonProperty("type") + private String type = "object"; + + @JsonProperty("properties") + private Map properties; + + @JsonProperty("required") + private List required; + + /** + * Gets the schema type indicator (always {@code "object"}). + * + * @return the type + */ + public String getType() { + return type; + } + + /** + * Sets the schema type indicator. + * + * @param type + * the type (typically {@code "object"}) + * @return this instance for method chaining + */ + public ElicitationSchema setType(String type) { + this.type = type; + return this; + } + + /** + * Gets the form field definitions, keyed by field name. + * + * @return the properties map + */ + public Map getProperties() { + return properties; + } + + /** + * Sets the form field definitions, keyed by field name. + * + * @param properties + * the properties map + * @return this instance for method chaining + */ + public ElicitationSchema setProperties(Map properties) { + this.properties = properties; + return this; + } + + /** + * Gets the list of required field names. + * + * @return the required field names, or {@code null} + */ + public List getRequired() { + return required; + } + + /** + * Sets the list of required field names. + * + * @param required + * the required field names + * @return this instance for method chaining + */ + public ElicitationSchema setRequired(List required) { + this.required = required; + return this; + } +} diff --git a/src/main/java/com/github/copilot/sdk/json/GetSessionMetadataResponse.java b/src/main/java/com/github/copilot/sdk/json/GetSessionMetadataResponse.java new file mode 100644 index 000000000..87c686f58 --- /dev/null +++ b/src/main/java/com/github/copilot/sdk/json/GetSessionMetadataResponse.java @@ -0,0 +1,15 @@ +package com.github.copilot.sdk.json; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Internal response object from getting session metadata by ID. + * + * @param session + * the session metadata, or {@code null} if not found + * @since 1.0.0 + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public record GetSessionMetadataResponse(@JsonProperty("session") SessionMetadata session) { +} diff --git a/src/main/java/com/github/copilot/sdk/json/InputOptions.java b/src/main/java/com/github/copilot/sdk/json/InputOptions.java new file mode 100644 index 000000000..9b0b6c8dd --- /dev/null +++ b/src/main/java/com/github/copilot/sdk/json/InputOptions.java @@ -0,0 +1,108 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk.json; + +/** + * Options for the {@link SessionUiApi#input(String, InputOptions)} convenience + * method. + * + * @since 1.0.0 + */ +public class InputOptions { + + private String title; + private String description; + private Integer minLength; + private Integer maxLength; + private String format; + private String defaultValue; + + /** Gets the title label for the input field. @return the title */ + public String getTitle() { + return title; + } + + /** + * Sets the title label for the input field. @param title the title @return this + */ + public InputOptions setTitle(String title) { + this.title = title; + return this; + } + + /** Gets the descriptive text shown below the field. @return the description */ + public String getDescription() { + return description; + } + + /** + * Sets the descriptive text shown below the field. @param description the + * description @return this + */ + public InputOptions setDescription(String description) { + this.description = description; + return this; + } + + /** Gets the minimum character length. @return the min length */ + public Integer getMinLength() { + return minLength; + } + + /** + * Sets the minimum character length. @param minLength the min length @return + * this + */ + public InputOptions setMinLength(Integer minLength) { + this.minLength = minLength; + return this; + } + + /** Gets the maximum character length. @return the max length */ + public Integer getMaxLength() { + return maxLength; + } + + /** + * Sets the maximum character length. @param maxLength the max length @return + * this + */ + public InputOptions setMaxLength(Integer maxLength) { + this.maxLength = maxLength; + return this; + } + + /** + * Gets the semantic format hint (e.g., {@code "email"}, {@code "uri"}, + * {@code "date"}, {@code "date-time"}). + * + * @return the format hint + */ + public String getFormat() { + return format; + } + + /** Sets the semantic format hint. @param format the format @return this */ + public InputOptions setFormat(String format) { + this.format = format; + return this; + } + + /** + * Gets the default value pre-populated in the field. @return the default value + */ + public String getDefaultValue() { + return defaultValue; + } + + /** + * Sets the default value pre-populated in the field. @param defaultValue the + * default value @return this + */ + public InputOptions setDefaultValue(String defaultValue) { + this.defaultValue = defaultValue; + return this; + } +} 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 eab3c789c..139f5238b 100644 --- a/src/main/java/com/github/copilot/sdk/json/ResumeSessionConfig.java +++ b/src/main/java/com/github/copilot/sdk/json/ResumeSessionConfig.java @@ -58,6 +58,8 @@ public class ResumeSessionConfig { private List disabledSkills; private InfiniteSessionConfig infiniteSessions; private Consumer onEvent; + private List commands; + private ElicitationHandler onElicitationRequest; /** * Gets the AI model to use. @@ -555,6 +557,56 @@ public ResumeSessionConfig setOnEvent(Consumer onEvent) { return this; } + /** + * Gets the slash commands registered for this session. + * + * @return the list of command definitions, or {@code null} + */ + public List getCommands() { + return commands == null ? null : Collections.unmodifiableList(commands); + } + + /** + * Sets slash commands registered for this session. + *

+ * When the CLI has a TUI, each command appears as {@code /name} for the user to + * invoke. The handler is called when the user executes the command. + * + * @param commands + * the list of command definitions + * @return this config for method chaining + * @see CommandDefinition + */ + public ResumeSessionConfig setCommands(List commands) { + this.commands = commands; + return this; + } + + /** + * Gets the elicitation request handler. + * + * @return the elicitation handler, or {@code null} + */ + public ElicitationHandler getOnElicitationRequest() { + return onElicitationRequest; + } + + /** + * Sets a handler for elicitation requests from the server or MCP tools. + *

+ * When provided, the server will route elicitation requests to this handler and + * report elicitation as a supported capability. + * + * @param onElicitationRequest + * the elicitation handler + * @return this config for method chaining + * @see ElicitationHandler + */ + public ResumeSessionConfig setOnElicitationRequest(ElicitationHandler onElicitationRequest) { + this.onElicitationRequest = onElicitationRequest; + return this; + } + /** * Creates a shallow clone of this {@code ResumeSessionConfig} instance. *

@@ -591,6 +643,8 @@ public ResumeSessionConfig clone() { copy.disabledSkills = this.disabledSkills != null ? new ArrayList<>(this.disabledSkills) : null; copy.infiniteSessions = this.infiniteSessions; copy.onEvent = this.onEvent; + copy.commands = this.commands != null ? new ArrayList<>(this.commands) : null; + copy.onElicitationRequest = this.onElicitationRequest; 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 31d88399a..7be9a6281 100644 --- a/src/main/java/com/github/copilot/sdk/json/ResumeSessionRequest.java +++ b/src/main/java/com/github/copilot/sdk/json/ResumeSessionRequest.java @@ -95,6 +95,12 @@ public final class ResumeSessionRequest { @JsonProperty("infiniteSessions") private InfiniteSessionConfig infiniteSessions; + @JsonProperty("commands") + private List commands; + + @JsonProperty("requestElicitation") + private Boolean requestElicitation; + /** Gets the session ID. @return the session ID */ public String getSessionId() { return sessionId; @@ -332,4 +338,24 @@ public InfiniteSessionConfig getInfiniteSessions() { public void setInfiniteSessions(InfiniteSessionConfig infiniteSessions) { this.infiniteSessions = infiniteSessions; } + + /** Gets the commands wire definitions. @return the commands */ + public List getCommands() { + return commands == null ? null : Collections.unmodifiableList(commands); + } + + /** Sets the commands wire definitions. @param commands the commands */ + public void setCommands(List commands) { + this.commands = commands; + } + + /** Gets the requestElicitation flag. @return the flag */ + public Boolean getRequestElicitation() { + return requestElicitation; + } + + /** Sets the requestElicitation flag. @param requestElicitation the flag */ + public void setRequestElicitation(Boolean requestElicitation) { + this.requestElicitation = requestElicitation; + } } diff --git a/src/main/java/com/github/copilot/sdk/json/ResumeSessionResponse.java b/src/main/java/com/github/copilot/sdk/json/ResumeSessionResponse.java index 654c1486c..8349c5d30 100644 --- a/src/main/java/com/github/copilot/sdk/json/ResumeSessionResponse.java +++ b/src/main/java/com/github/copilot/sdk/json/ResumeSessionResponse.java @@ -11,9 +11,12 @@ * @param workspacePath * the workspace path, or {@code null} if infinite sessions are * disabled + * @param capabilities + * the capabilities reported by the host, or {@code null} * @since 1.0.0 */ @JsonInclude(JsonInclude.Include.NON_NULL) public record ResumeSessionResponse(@JsonProperty("sessionId") String sessionId, - @JsonProperty("workspacePath") String workspacePath) { + @JsonProperty("workspacePath") String workspacePath, + @JsonProperty("capabilities") SessionCapabilities capabilities) { } diff --git a/src/main/java/com/github/copilot/sdk/json/SessionCapabilities.java b/src/main/java/com/github/copilot/sdk/json/SessionCapabilities.java new file mode 100644 index 000000000..4eb4fc025 --- /dev/null +++ b/src/main/java/com/github/copilot/sdk/json/SessionCapabilities.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk.json; + +/** + * Represents the capabilities reported by the host for a session. + *

+ * Capabilities are populated from the session create/resume response and + * updated in real time via {@code capabilities.changed} events. + * + * @since 1.0.0 + */ +public class SessionCapabilities { + + private SessionUiCapabilities ui; + + /** + * Gets the UI-related capabilities. + * + * @return the UI capabilities, or {@code null} if not reported + */ + public SessionUiCapabilities getUi() { + return ui; + } + + /** + * Sets the UI-related capabilities. + * + * @param ui + * the UI capabilities + * @return this instance for method chaining + */ + public SessionCapabilities setUi(SessionUiCapabilities ui) { + this.ui = ui; + return this; + } +} 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 76c15660d..5dcd39788 100644 --- a/src/main/java/com/github/copilot/sdk/json/SessionConfig.java +++ b/src/main/java/com/github/copilot/sdk/json/SessionConfig.java @@ -58,6 +58,8 @@ public class SessionConfig { private List disabledSkills; private String configDir; private Consumer onEvent; + private List commands; + private ElicitationHandler onElicitationRequest; /** * Gets the custom session ID. @@ -595,6 +597,56 @@ public SessionConfig setOnEvent(Consumer onEvent) { return this; } + /** + * Gets the slash commands registered for this session. + * + * @return the list of command definitions, or {@code null} + */ + public List getCommands() { + return commands == null ? null : Collections.unmodifiableList(commands); + } + + /** + * Sets slash commands registered for this session. + *

+ * When the CLI has a TUI, each command appears as {@code /name} for the user to + * invoke. The handler is called when the user executes the command. + * + * @param commands + * the list of command definitions + * @return this config instance for method chaining + * @see CommandDefinition + */ + public SessionConfig setCommands(List commands) { + this.commands = commands; + return this; + } + + /** + * Gets the elicitation request handler. + * + * @return the elicitation handler, or {@code null} + */ + public ElicitationHandler getOnElicitationRequest() { + return onElicitationRequest; + } + + /** + * Sets a handler for elicitation requests from the server or MCP tools. + *

+ * When provided, the server will route elicitation requests to this handler and + * report elicitation as a supported capability. + * + * @param onElicitationRequest + * the elicitation handler + * @return this config instance for method chaining + * @see ElicitationHandler + */ + public SessionConfig setOnElicitationRequest(ElicitationHandler onElicitationRequest) { + this.onElicitationRequest = onElicitationRequest; + return this; + } + /** * Creates a shallow clone of this {@code SessionConfig} instance. *

@@ -631,6 +683,8 @@ public SessionConfig clone() { copy.disabledSkills = this.disabledSkills != null ? new ArrayList<>(this.disabledSkills) : null; copy.configDir = this.configDir; copy.onEvent = this.onEvent; + copy.commands = this.commands != null ? new ArrayList<>(this.commands) : null; + copy.onElicitationRequest = this.onElicitationRequest; return copy; } } diff --git a/src/main/java/com/github/copilot/sdk/json/SessionUiApi.java b/src/main/java/com/github/copilot/sdk/json/SessionUiApi.java new file mode 100644 index 000000000..bfc9fc161 --- /dev/null +++ b/src/main/java/com/github/copilot/sdk/json/SessionUiApi.java @@ -0,0 +1,85 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk.json; + +import java.util.concurrent.CompletableFuture; + +/** + * Provides UI methods for eliciting information from the user during a session. + *

+ * All methods on this interface throw {@link IllegalStateException} if the host + * does not report elicitation support via + * {@link com.github.copilot.sdk.CopilotSession#getCapabilities()}. Check + * {@code session.getCapabilities().getUi()?.getElicitation() == true} before + * calling. + * + *

Example Usage

+ * + *
{@code
+ * if (Boolean.TRUE
+ * 		.equals(session.getCapabilities().getUi() != null && session.getCapabilities().getUi().getElicitation())) {
+ * 	boolean confirmed = session.getUi().confirm("Are you sure?").get();
+ * }
+ * }
+ * + * @see com.github.copilot.sdk.CopilotSession#getUi() + * @since 1.0.0 + */ +public interface SessionUiApi { + + /** + * Shows a generic elicitation dialog with a custom schema. + * + * @param params + * the elicitation parameters including message and schema + * @return a future that resolves with the {@link ElicitationResult} + * @throws IllegalStateException + * if the host does not support elicitation + */ + CompletableFuture elicitation(ElicitationParams params); + + /** + * Shows a confirmation dialog and returns the user's boolean answer. + *

+ * Returns {@code false} if the user declines or cancels. + * + * @param message + * the message to display + * @return a future that resolves to {@code true} if the user confirmed + * @throws IllegalStateException + * if the host does not support elicitation + */ + CompletableFuture confirm(String message); + + /** + * Shows a selection dialog with the given options. + *

+ * Returns the selected value, or {@code null} if the user declines/cancels. + * + * @param message + * the message to display + * @param options + * the options to present + * @return a future that resolves to the selected string, or {@code null} + * @throws IllegalStateException + * if the host does not support elicitation + */ + CompletableFuture select(String message, String[] options); + + /** + * Shows a text input dialog. + *

+ * Returns the entered text, or {@code null} if the user declines/cancels. + * + * @param message + * the message to display + * @param options + * optional input field options, or {@code null} + * @return a future that resolves to the entered string, or {@code null} + * @throws IllegalStateException + * if the host does not support elicitation + */ + CompletableFuture input(String message, InputOptions options); +} diff --git a/src/main/java/com/github/copilot/sdk/json/SessionUiCapabilities.java b/src/main/java/com/github/copilot/sdk/json/SessionUiCapabilities.java new file mode 100644 index 000000000..9b8e0b587 --- /dev/null +++ b/src/main/java/com/github/copilot/sdk/json/SessionUiCapabilities.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk.json; + +/** + * UI-specific capability flags for a session. + * + * @since 1.0.0 + */ +public class SessionUiCapabilities { + + private Boolean elicitation; + + /** + * Returns whether the host supports interactive elicitation dialogs. + * + * @return {@code true} if elicitation is supported, {@code false} or + * {@code null} otherwise + */ + public Boolean getElicitation() { + return elicitation; + } + + /** + * Sets whether the host supports interactive elicitation dialogs. + * + * @param elicitation + * {@code true} if elicitation is supported + * @return this instance for method chaining + */ + public SessionUiCapabilities setElicitation(Boolean elicitation) { + this.elicitation = elicitation; + return this; + } +} From 4001135367c73413f74b4f6e4cd8c3490b4b4cda Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 10:58:53 +0000 Subject: [PATCH 39/80] Add tests, documentation, and update .lastmerge to f7fd757 Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/16d575c4-83f4-4d20-99d9-b48635b3791d Co-authored-by: edburns <75821+edburns@users.noreply.github.com> --- .lastmerge | 2 +- README.md | 2 +- src/site/markdown/advanced.md | 137 +++++++++++++ src/site/markdown/index.md | 2 +- .../com/github/copilot/sdk/CommandsTest.java | 138 +++++++++++++ .../copilot/sdk/CopilotSessionTest.java | 28 +++ .../github/copilot/sdk/ElicitationTest.java | 191 ++++++++++++++++++ 7 files changed, 497 insertions(+), 3 deletions(-) create mode 100644 src/test/java/com/github/copilot/sdk/CommandsTest.java create mode 100644 src/test/java/com/github/copilot/sdk/ElicitationTest.java diff --git a/.lastmerge b/.lastmerge index a0cf76b72..0d0067b5b 100644 --- a/.lastmerge +++ b/.lastmerge @@ -1 +1 @@ -40887393a9e687dacc141a645799441b0313ff15 +f7fd7577109d64e261456b16c49baa56258eae4e diff --git a/README.md b/README.md index 3010b6839..f71424950 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Java SDK for programmatic control of GitHub Copilot CLI, enabling you to build A ### Requirements - Java 17 or later. **JDK 25 recommended**. Selecting JDK 25 enables the use of virtual threads, as shown in the [Quick Start](#quick-start). -- GitHub Copilot 1.0.15-0 or later installed and in `PATH` (or provide custom `cliPath`) +- GitHub Copilot 1.0.17 or later installed and in `PATH` (or provide custom `cliPath`) ### Maven diff --git a/src/site/markdown/advanced.md b/src/site/markdown/advanced.md index bc9302840..598acc2f7 100644 --- a/src/site/markdown/advanced.md +++ b/src/site/markdown/advanced.md @@ -1093,6 +1093,143 @@ See [TelemetryConfig](apidocs/com/github/copilot/sdk/json/TelemetryConfig.html) --- +## Slash Commands + +Register custom slash commands that users can invoke from the CLI TUI with `/commandname`. + +### Registering Commands + +```java +var config = new SessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setCommands(List.of( + new CommandDefinition() + .setName("deploy") + .setDescription("Deploy the current branch") + .setHandler(context -> { + System.out.println("Deploying with args: " + context.getArgs()); + // perform deployment ... + return CompletableFuture.completedFuture(null); + }), + new CommandDefinition() + .setName("rollback") + .setDescription("Roll back the last deployment") + .setHandler(context -> { + // perform rollback ... + return CompletableFuture.completedFuture(null); + }) + )); + +try (CopilotClient client = new CopilotClient()) { + client.start().get(); + var session = client.createSession(config).get(); + // Users can now type /deploy or /rollback in the TUI +} +``` + +Each `CommandDefinition` requires a `name` (without the leading `/`), an optional `description` shown in the TUI's command completion UI, and a `CommandHandler` that is invoked when the user executes the command. + +The `CommandContext` passed to the handler provides: +- `getSessionId()` — the ID of the session where the command was invoked +- `getCommand()` — the full command text (e.g., `/deploy production`) +- `getCommandName()` — command name without the leading `/` (e.g., `deploy`) +- `getArgs()` — the argument string after the command name (e.g., `production`) + +--- + +## Elicitation (UI Dialogs) + +Elicitation allows your application to present structured UI dialogs to the user. There are two directions: + +1. **Incoming** — The server or an MCP tool requests input from the user via your `onElicitationRequest` handler. +2. **Outgoing** — Your session-side code proactively requests input via `session.getUi()`. + +### Incoming Elicitation Handler + +Register a handler to receive elicitation requests from the server: + +```java +var config = new SessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setOnElicitationRequest(context -> { + System.out.println("Elicitation request: " + context.getMessage()); + // Show the form to the user ... + var content = Map.of("confirmed", true); + return CompletableFuture.completedFuture( + new ElicitationResult() + .setAction(ElicitationResultAction.ACCEPT) + .setContent(content) + ); + }); +``` + +When `onElicitationRequest` is set, the SDK reports elicitation as a supported capability and the server will route elicitation requests to your handler. + +### Session Capabilities + +After `createSession` or `resumeSession`, check `session.getCapabilities()` to see what the host supports: + +```java +var session = client.createSession(config).get(); + +var caps = session.getCapabilities(); +if (caps.getUi() != null && Boolean.TRUE.equals(caps.getUi().getElicitation())) { + System.out.println("Elicitation is supported"); +} +``` + +Capabilities are updated in real time when a `capabilities.changed` event is received. + +### Outgoing Elicitation via `session.getUi()` + +If the host reports elicitation support, you can call the convenience methods on `session.getUi()`: + +```java +var ui = session.getUi(); + +// Boolean confirmation +boolean confirmed = ui.confirm("Are you sure you want to proceed?").get(); + +// Selection from options +String choice = ui.select("Choose an environment", new String[]{"dev", "staging", "prod"}).get(); + +// Text input +String value = ui.input("Enter your name", null).get(); + +// Custom schema +var result = ui.elicitation(new ElicitationParams() + .setMessage("Enter deployment details") + .setRequestedSchema(new ElicitationSchema() + .setProperties(Map.of( + "branch", Map.of("type", "string"), + "environment", Map.of("type", "string", "enum", List.of("dev", "staging", "prod")) + )) + .setRequired(List.of("branch", "environment")) + )).get(); +``` + +All `getUi()` methods throw `IllegalStateException` if the host does not support elicitation. Always check capabilities first. + +--- + +## Getting Session Metadata by ID + +Retrieve metadata for a specific session without listing all sessions: + +```java +SessionMetadata metadata = client.getSessionMetadata("session-123").get(); +if (metadata != null) { + System.out.println("Session: " + metadata.getSessionId()); + System.out.println("Started: " + metadata.getStartTime()); +} else { + System.out.println("Session not found"); +} +``` + +This is more efficient than `listSessions()` when you already know the session ID, as it performs a direct O(1) lookup instead of scanning all sessions. + +--- + ## Next Steps - 📖 **[Documentation](documentation.html)** - Core concepts, events, streaming, models, tool filtering, reasoning effort diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md index 2f93c4ce9..b599484d9 100644 --- a/src/site/markdown/index.md +++ b/src/site/markdown/index.md @@ -9,7 +9,7 @@ Welcome to the documentation for the **GitHub Copilot SDK for Java** — a Java ### Requirements - Java 17 or later -- GitHub Copilot CLI 0.0.411-1 or later installed and in PATH (or provide custom `cliPath`) +- GitHub Copilot CLI 1.0.17 or later installed and in PATH (or provide custom `cliPath`) ### Installation diff --git a/src/test/java/com/github/copilot/sdk/CommandsTest.java b/src/test/java/com/github/copilot/sdk/CommandsTest.java new file mode 100644 index 000000000..dad26afbb --- /dev/null +++ b/src/test/java/com/github/copilot/sdk/CommandsTest.java @@ -0,0 +1,138 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.junit.jupiter.api.Test; + +import com.github.copilot.sdk.json.CommandContext; +import com.github.copilot.sdk.json.CommandDefinition; +import com.github.copilot.sdk.json.CommandHandler; +import com.github.copilot.sdk.json.CommandWireDefinition; +import com.github.copilot.sdk.json.PermissionHandler; +import com.github.copilot.sdk.json.ResumeSessionConfig; +import com.github.copilot.sdk.json.SessionConfig; + +/** + * Unit tests for the Commands feature (CommandDefinition, CommandContext, + * SessionConfig.commands, ResumeSessionConfig.commands, and the wire + * representation). + * + *

+ * Ported from {@code CommandsTests.cs} in the upstream dotnet SDK. + *

+ */ +class CommandsTest { + + @Test + void commandDefinitionHasRequiredProperties() { + CommandHandler handler = context -> CompletableFuture.completedFuture(null); + var cmd = new CommandDefinition().setName("deploy").setDescription("Deploy the app").setHandler(handler); + + assertEquals("deploy", cmd.getName()); + assertEquals("Deploy the app", cmd.getDescription()); + assertNotNull(cmd.getHandler()); + } + + @Test + void commandContextHasAllProperties() { + var ctx = new CommandContext().setSessionId("session-1").setCommand("/deploy production") + .setCommandName("deploy").setArgs("production"); + + assertEquals("session-1", ctx.getSessionId()); + assertEquals("/deploy production", ctx.getCommand()); + assertEquals("deploy", ctx.getCommandName()); + assertEquals("production", ctx.getArgs()); + } + + @Test + void sessionConfigCommandsAreCloned() { + CommandHandler handler = ctx -> CompletableFuture.completedFuture(null); + var config = new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setCommands(List.of(new CommandDefinition().setName("deploy").setHandler(handler))); + + var clone = config.clone(); + + assertNotNull(clone.getCommands()); + assertEquals(1, clone.getCommands().size()); + assertEquals("deploy", clone.getCommands().get(0).getName()); + + // Collections should be independent — clone list is a copy + assertNotSame(config.getCommands(), clone.getCommands()); + } + + @Test + void resumeConfigCommandsAreCloned() { + CommandHandler handler = ctx -> CompletableFuture.completedFuture(null); + var config = new ResumeSessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setCommands(List.of(new CommandDefinition().setName("deploy").setHandler(handler))); + + var clone = config.clone(); + + assertNotNull(clone.getCommands()); + assertEquals(1, clone.getCommands().size()); + assertEquals("deploy", clone.getCommands().get(0).getName()); + } + + @Test + void buildCreateRequestIncludesCommandWireDefinitions() { + CommandHandler handler = ctx -> CompletableFuture.completedFuture(null); + var config = new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setCommands( + List.of(new CommandDefinition().setName("deploy").setDescription("Deploy").setHandler(handler), + new CommandDefinition().setName("rollback").setHandler(handler))); + + var request = SessionRequestBuilder.buildCreateRequest(config); + + assertNotNull(request.getCommands()); + assertEquals(2, request.getCommands().size()); + assertEquals("deploy", request.getCommands().get(0).getName()); + assertEquals("Deploy", request.getCommands().get(0).getDescription()); + assertEquals("rollback", request.getCommands().get(1).getName()); + assertNull(request.getCommands().get(1).getDescription()); + } + + @Test + void buildResumeRequestIncludesCommandWireDefinitions() { + CommandHandler handler = ctx -> CompletableFuture.completedFuture(null); + var config = new ResumeSessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setCommands( + List.of(new CommandDefinition().setName("deploy").setDescription("Deploy").setHandler(handler))); + + var request = SessionRequestBuilder.buildResumeRequest("session-1", config); + + assertNotNull(request.getCommands()); + assertEquals(1, request.getCommands().size()); + assertEquals("deploy", request.getCommands().get(0).getName()); + assertEquals("Deploy", request.getCommands().get(0).getDescription()); + } + + @Test + void buildCreateRequestWithNoCommandsHasNullCommandsList() { + var config = new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL); + + var request = SessionRequestBuilder.buildCreateRequest(config); + + assertNull(request.getCommands()); + } + + @Test + void commandWireDefinitionHasNameAndDescription() { + var wire = new CommandWireDefinition("deploy", "Deploy the app"); + + assertEquals("deploy", wire.getName()); + assertEquals("Deploy the app", wire.getDescription()); + } + + @Test + void commandWireDefinitionNullDescriptionAllowed() { + var wire = new CommandWireDefinition("rollback", null); + + assertEquals("rollback", wire.getName()); + assertNull(wire.getDescription()); + } +} diff --git a/src/test/java/com/github/copilot/sdk/CopilotSessionTest.java b/src/test/java/com/github/copilot/sdk/CopilotSessionTest.java index 787312cef..39406d260 100644 --- a/src/test/java/com/github/copilot/sdk/CopilotSessionTest.java +++ b/src/test/java/com/github/copilot/sdk/CopilotSessionTest.java @@ -7,6 +7,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -821,4 +822,31 @@ void testSessionListFilterFluentAPI() throws Exception { session.close(); } } + + /** + * Verifies that getSessionMetadata returns metadata for a known session ID. + * + * @see Snapshot: session/should_get_session_metadata_by_id + */ + @Test + void testShouldGetSessionMetadataById() throws Exception { + ctx.configureForTest("session", "should_get_session_metadata_by_id"); + + try (CopilotClient client = ctx.createClient()) { + var session = client + .createSession(new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get(); + + session.sendAndWait(new MessageOptions().setPrompt("Say hello")).get(60, TimeUnit.SECONDS); + + var metadata = client.getSessionMetadata(session.getSessionId()).get(30, TimeUnit.SECONDS); + assertNotNull(metadata, "Metadata should not be null for known session"); + assertEquals(session.getSessionId(), metadata.getSessionId(), "Metadata session ID should match"); + + // A non-existent session should return null + var notFound = client.getSessionMetadata("non-existent-session-id").get(30, TimeUnit.SECONDS); + assertNull(notFound, "Non-existent session should return null"); + + session.close(); + } + } } diff --git a/src/test/java/com/github/copilot/sdk/ElicitationTest.java b/src/test/java/com/github/copilot/sdk/ElicitationTest.java new file mode 100644 index 000000000..330153dd2 --- /dev/null +++ b/src/test/java/com/github/copilot/sdk/ElicitationTest.java @@ -0,0 +1,191 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +import org.junit.jupiter.api.Test; + +import com.github.copilot.sdk.json.ElicitationContext; +import com.github.copilot.sdk.json.ElicitationHandler; +import com.github.copilot.sdk.json.ElicitationParams; +import com.github.copilot.sdk.json.ElicitationResult; +import com.github.copilot.sdk.json.ElicitationResultAction; +import com.github.copilot.sdk.json.ElicitationSchema; +import com.github.copilot.sdk.json.InputOptions; +import com.github.copilot.sdk.json.PermissionHandler; +import com.github.copilot.sdk.json.ResumeSessionConfig; +import com.github.copilot.sdk.json.SessionCapabilities; +import com.github.copilot.sdk.json.SessionConfig; +import com.github.copilot.sdk.json.SessionUiCapabilities; + +/** + * Unit tests for the Elicitation feature and Session Capabilities. + * + *

+ * Ported from {@code ElicitationTests.cs} in the upstream dotnet SDK. + *

+ */ +class ElicitationTest { + + @Test + void sessionCapabilitiesTypesAreProperlyStructured() { + var capabilities = new SessionCapabilities().setUi(new SessionUiCapabilities().setElicitation(true)); + + assertNotNull(capabilities.getUi()); + assertTrue(capabilities.getUi().getElicitation()); + + // Test with null UI + var emptyCapabilities = new SessionCapabilities(); + assertNull(emptyCapabilities.getUi()); + assertNull(emptyCapabilities.getUi()); + } + + @Test + void defaultCapabilitiesAreEmpty() { + var capabilities = new SessionCapabilities(); + + assertNull(capabilities.getUi()); + } + + @Test + void elicitationResultActionValues() { + assertEquals("accept", ElicitationResultAction.ACCEPT.getValue()); + assertEquals("decline", ElicitationResultAction.DECLINE.getValue()); + assertEquals("cancel", ElicitationResultAction.CANCEL.getValue()); + } + + @Test + void elicitationResultHasActionAndContent() { + var content = Map.of("name", (Object) "Alice"); + var result = new ElicitationResult().setAction(ElicitationResultAction.ACCEPT).setContent(content); + + assertEquals(ElicitationResultAction.ACCEPT, result.getAction()); + assertEquals(content, result.getContent()); + } + + @Test + void elicitationSchemaHasTypeAndProperties() { + var properties = Map.of("name", (Object) Map.of("type", "string")); + var schema = new ElicitationSchema().setType("object").setProperties(properties).setRequired(List.of("name")); + + assertEquals("object", schema.getType()); + assertEquals(properties, schema.getProperties()); + assertEquals(List.of("name"), schema.getRequired()); + } + + @Test + void elicitationSchemaDefaultTypeIsObject() { + var schema = new ElicitationSchema(); + + assertEquals("object", schema.getType()); + } + + @Test + void elicitationContextHasAllProperties() { + var properties = Map.of("field", (Object) Map.of("type", "string")); + var schema = new ElicitationSchema().setProperties(properties); + + var ctx = new ElicitationContext().setSessionId("session-1").setMessage("Please enter your name") + .setRequestedSchema(schema).setMode("form").setElicitationSource("mcp-server").setUrl(null); + + assertEquals("session-1", ctx.getSessionId()); + assertEquals("Please enter your name", ctx.getMessage()); + assertEquals(schema, ctx.getRequestedSchema()); + assertEquals("form", ctx.getMode()); + assertEquals("mcp-server", ctx.getElicitationSource()); + assertNull(ctx.getUrl()); + } + + @Test + void elicitationParamsHasMessageAndSchema() { + var schema = new ElicitationSchema().setProperties(Map.of("field", (Object) Map.of("type", "string"))); + var params = new ElicitationParams().setMessage("Enter name").setRequestedSchema(schema); + + assertEquals("Enter name", params.getMessage()); + assertEquals(schema, params.getRequestedSchema()); + } + + @Test + void inputOptionsHasAllFields() { + var opts = new InputOptions().setTitle("My Title").setDescription("My Desc").setMinLength(1).setMaxLength(100) + .setFormat("email").setDefaultValue("default@example.com"); + + assertEquals("My Title", opts.getTitle()); + assertEquals("My Desc", opts.getDescription()); + assertEquals(1, opts.getMinLength()); + assertEquals(100, opts.getMaxLength()); + assertEquals("email", opts.getFormat()); + assertEquals("default@example.com", opts.getDefaultValue()); + } + + @Test + void sessionConfigOnElicitationRequestIsCloned() { + ElicitationHandler handler = ctx -> CompletableFuture + .completedFuture(new ElicitationResult().setAction(ElicitationResultAction.ACCEPT)); + + var config = new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setOnElicitationRequest(handler); + + var clone = config.clone(); + + // Handler reference is shared (not deep-cloned), but the field is copied + assertNotNull(clone.getOnElicitationRequest()); + assertSame(handler, clone.getOnElicitationRequest()); + } + + @Test + void resumeConfigOnElicitationRequestIsCloned() { + ElicitationHandler handler = ctx -> CompletableFuture + .completedFuture(new ElicitationResult().setAction(ElicitationResultAction.CANCEL)); + + var config = new ResumeSessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setOnElicitationRequest(handler); + + var clone = config.clone(); + + assertNotNull(clone.getOnElicitationRequest()); + assertSame(handler, clone.getOnElicitationRequest()); + } + + @Test + void buildCreateRequestSetsRequestElicitationWhenHandlerPresent() { + ElicitationHandler handler = ctx -> CompletableFuture + .completedFuture(new ElicitationResult().setAction(ElicitationResultAction.ACCEPT)); + + var config = new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setOnElicitationRequest(handler); + + var request = SessionRequestBuilder.buildCreateRequest(config); + + assertTrue(Boolean.TRUE.equals(request.getRequestElicitation())); + } + + @Test + void buildCreateRequestDoesNotSetRequestElicitationWhenNoHandler() { + var config = new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL); + + var request = SessionRequestBuilder.buildCreateRequest(config); + + assertNull(request.getRequestElicitation()); + } + + @Test + void buildResumeRequestSetsRequestElicitationWhenHandlerPresent() { + ElicitationHandler handler = ctx -> CompletableFuture + .completedFuture(new ElicitationResult().setAction(ElicitationResultAction.ACCEPT)); + + var config = new ResumeSessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setOnElicitationRequest(handler); + + var request = SessionRequestBuilder.buildResumeRequest("session-1", config); + + assertTrue(Boolean.TRUE.equals(request.getRequestElicitation())); + } +} From 2da6b5a8334f1fc9c696858401856e277d3e1948 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 11:01:31 +0000 Subject: [PATCH 40/80] Fix code review issues: duplicate assertion, copyright header, Javadoc example Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/16d575c4-83f4-4d20-99d9-b48635b3791d Co-authored-by: edburns <75821+edburns@users.noreply.github.com> --- .../github/copilot/sdk/json/GetSessionMetadataResponse.java | 4 ++++ src/main/java/com/github/copilot/sdk/json/SessionUiApi.java | 4 ++-- src/test/java/com/github/copilot/sdk/ElicitationTest.java | 1 - 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/github/copilot/sdk/json/GetSessionMetadataResponse.java b/src/main/java/com/github/copilot/sdk/json/GetSessionMetadataResponse.java index 87c686f58..eeceb4177 100644 --- a/src/main/java/com/github/copilot/sdk/json/GetSessionMetadataResponse.java +++ b/src/main/java/com/github/copilot/sdk/json/GetSessionMetadataResponse.java @@ -1,3 +1,7 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + package com.github.copilot.sdk.json; import com.fasterxml.jackson.annotation.JsonInclude; diff --git a/src/main/java/com/github/copilot/sdk/json/SessionUiApi.java b/src/main/java/com/github/copilot/sdk/json/SessionUiApi.java index bfc9fc161..6dc583457 100644 --- a/src/main/java/com/github/copilot/sdk/json/SessionUiApi.java +++ b/src/main/java/com/github/copilot/sdk/json/SessionUiApi.java @@ -18,8 +18,8 @@ *

Example Usage

* *
{@code
- * if (Boolean.TRUE
- * 		.equals(session.getCapabilities().getUi() != null && session.getCapabilities().getUi().getElicitation())) {
+ * var caps = session.getCapabilities();
+ * if (caps.getUi() != null && Boolean.TRUE.equals(caps.getUi().getElicitation())) {
  * 	boolean confirmed = session.getUi().confirm("Are you sure?").get();
  * }
  * }
diff --git a/src/test/java/com/github/copilot/sdk/ElicitationTest.java b/src/test/java/com/github/copilot/sdk/ElicitationTest.java index 330153dd2..d6e2ac0b5 100644 --- a/src/test/java/com/github/copilot/sdk/ElicitationTest.java +++ b/src/test/java/com/github/copilot/sdk/ElicitationTest.java @@ -44,7 +44,6 @@ void sessionCapabilitiesTypesAreProperlyStructured() { // Test with null UI var emptyCapabilities = new SessionCapabilities(); assertNull(emptyCapabilities.getUi()); - assertNull(emptyCapabilities.getUi()); } @Test From 7060eed9c996e58f9c3896a72e65fa108dfc509b Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Mon, 6 Apr 2026 13:12:05 -0400 Subject: [PATCH 41/80] Update src/main/java/com/github/copilot/sdk/CopilotSession.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/main/java/com/github/copilot/sdk/CopilotSession.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/github/copilot/sdk/CopilotSession.java b/src/main/java/com/github/copilot/sdk/CopilotSession.java index 768f0adaa..23b1b5368 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotSession.java +++ b/src/main/java/com/github/copilot/sdk/CopilotSession.java @@ -724,7 +724,7 @@ private void handleBroadcastEventAsync(AbstractSessionEvent event) { executePermissionAndRespondAsync(data.requestId(), data.permissionRequest(), handler); } else if (event instanceof CommandExecuteEvent cmdEvent) { var data = cmdEvent.getData(); - if (data == null || data.requestId() == null) { + if (data == null || data.requestId() == null || data.commandName() == null) { return; } executeCommandAndRespondAsync(data.requestId(), data.commandName(), data.command(), data.args()); From 0bd084c6a6c8c06a6becf63d8e2efc4d51b5ef68 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Tue, 31 Mar 2026 16:33:52 -0400 Subject: [PATCH 42/80] Reapply "On branch edburns/spotless-agentic-workflow-42" This reverts commit 05d06d97f398a092897725a7651af10f96a047da. --- .github/copilot-instructions.md | 12 ++++++++++++ .github/workflows/copilot-setup-steps.yml | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index d7dafb081..e3a8eb275 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -244,6 +244,18 @@ This SDK is designed to be **lightweight with minimal dependencies**: 5. Check for security vulnerabilities 6. Get team approval for non-trivial additions +## Pre-commit Hooks and Formatting (Coding Agent) + +The repository has a pre-commit hook (`.githooks/pre-commit`) that is **automatically enabled** in the Copilot coding agent environment via `copilot-setup-steps.yml`. The hook runs `mvn spotless:check` on any commit that includes changes under `src/`. + +**If a commit fails due to the pre-commit hook:** + +1. Run `mvn spotless:apply` to auto-fix formatting issues. +2. Re-stage the changed files with `git add -u`. +3. Retry the commit. + +**Best practice:** Always run `mvn spotless:apply` before committing Java source changes to avoid hook failures in the first place. If you forget and the hook rejects the commit, follow the three steps above and continue. + ## Commit and PR Guidelines ### Commit Messages diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 6a0cdec5b..8d8aa75c9 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -41,6 +41,10 @@ jobs: distribution: 'temurin' cache: 'maven' + # Enable pre-commit hooks so Spotless formatting is enforced on every commit + - name: Enable pre-commit hooks + run: git config core.hooksPath .githooks + # Verify installations - name: Verify tool installations run: | @@ -50,4 +54,6 @@ jobs: java -version gh --version gh aw version + echo "--- Git hooks path ---" + git config core.hooksPath echo "✅ All tools installed successfully" From 99d456780806e148292e25b51d0f8449545c00bd Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Tue, 31 Mar 2026 16:33:56 -0400 Subject: [PATCH 43/80] Reapply "Update .github/workflows/copilot-setup-steps.yml" This reverts commit afc34c439dd3e393840fe3c213ccc4d7b12fed39. --- .github/workflows/copilot-setup-steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 8d8aa75c9..145629457 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -41,7 +41,7 @@ jobs: distribution: 'temurin' cache: 'maven' - # Enable pre-commit hooks so Spotless formatting is enforced on every commit + # Enable repository pre-commit hooks (including Spotless checks for relevant source changes) - name: Enable pre-commit hooks run: git config core.hooksPath .githooks From e665e2100ab90262ba9e3a4d2fc04ca1f45c339e Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Mon, 6 Apr 2026 13:27:33 -0400 Subject: [PATCH 44/80] On branch edburns/re-enable-pre-commit-hooks modified: .github/copilot-instructions.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apply @Copilot review recommendation. > This new section says the pre-commit hook is “automatically enabled” via `copilot-setup-steps.yml`, but earlier in the same document (and in CONTRIBUTING/README) the hook is described as something developers must manually enable with `git config core.hooksPath .githooks`. Please clarify the scope (e.g., auto-enabled only in the Copilot coding agent environment; local development still requires manual enablement) to avoid conflicting guidance, and consider linking explicitly to `.github/workflows/copilot-setup-steps.yml` for precision. Signed-off-by: Ed Burns --- .github/copilot-instructions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index e3a8eb275..284e2b800 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -104,7 +104,7 @@ When porting from .NET: - 4-space indentation (enforced by Spotless with Eclipse formatter) - Fluent setter pattern for configuration classes (e.g., `new SessionConfig().setModel("gpt-5").setTools(tools)`) - Public APIs require Javadoc (enforced by Checkstyle, except `json` and `events` packages) -- Pre-commit hook runs `mvn spotless:check` - enable with: `git config core.hooksPath .githooks` +- Pre-commit hook runs `mvn spotless:check` - Must be manually enabled with: `git config core.hooksPath .githooks`, except in the Copilot coding agent environment. This hook is explicitly enabled in the Copilot coding agent environment. See [copilot-setup-steps.yml](workflows/copilot-setup-steps.yml). ### Handler Pattern From 8cb5827b9423bdf91fe0c1cf8ac0abb1fec53a11 Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Mon, 6 Apr 2026 13:40:27 -0400 Subject: [PATCH 45/80] Update README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f71424950..677389c6e 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Java SDK for programmatic control of GitHub Copilot CLI, enabling you to build A ### Requirements - Java 17 or later. **JDK 25 recommended**. Selecting JDK 25 enables the use of virtual threads, as shown in the [Quick Start](#quick-start). -- GitHub Copilot 1.0.17 or later installed and in `PATH` (or provide custom `cliPath`) +- GitHub Copilot CLI 1.0.17 or later installed and in `PATH` (or provide custom `cliPath`) ### Maven From e365e05e692ff57f6371c43837e8db7ec299e6a0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 17:42:42 +0000 Subject: [PATCH 46/80] Fix invalid Java ?. operator in SessionUiApi Javadoc prose Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/b5d79053-ae26-4c98-9047-b2457c08b0b8 Co-authored-by: brunoborges <129743+brunoborges@users.noreply.github.com> --- src/main/java/com/github/copilot/sdk/json/SessionUiApi.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/github/copilot/sdk/json/SessionUiApi.java b/src/main/java/com/github/copilot/sdk/json/SessionUiApi.java index 6dc583457..f0a43f261 100644 --- a/src/main/java/com/github/copilot/sdk/json/SessionUiApi.java +++ b/src/main/java/com/github/copilot/sdk/json/SessionUiApi.java @@ -12,8 +12,9 @@ * All methods on this interface throw {@link IllegalStateException} if the host * does not report elicitation support via * {@link com.github.copilot.sdk.CopilotSession#getCapabilities()}. Check - * {@code session.getCapabilities().getUi()?.getElicitation() == true} before - * calling. + * {@code session.getCapabilities().getUi() != null && + * Boolean.TRUE.equals(session.getCapabilities().getUi().getElicitation())} + * before calling. * *

Example Usage

* From 8835bd0fe108bff43844c0b678a0143d735bcb17 Mon Sep 17 00:00:00 2001 From: brunoborges <129743+brunoborges@users.noreply.github.com> Date: Mon, 6 Apr 2026 20:29:56 +0000 Subject: [PATCH 47/80] Update JaCoCo coverage badge --- .github/badges/jacoco.svg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/badges/jacoco.svg b/.github/badges/jacoco.svg index 482adb13b..a310734d0 100644 --- a/.github/badges/jacoco.svg +++ b/.github/badges/jacoco.svg @@ -6,13 +6,13 @@ - + coverage coverage - 84.7% - 84.7% + 78.3% + 78.3% From 538f138ad33680771cdb132b1c5ea9d856d49fa4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 21:18:16 +0000 Subject: [PATCH 48/80] Initial plan From 2bd1bf82152887efe1d6e5c2edf2568faeb0b3d7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 21:50:36 +0000 Subject: [PATCH 49/80] Add tests to increase JaCoCo coverage from 78.7% to 85.2% Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/ee2608f6-2d6c-477e-9f79-a2968dec2436 Co-authored-by: edburns <75821+edburns@users.noreply.github.com> --- .../com/github/copilot/sdk/AgentInfoTest.java | 64 ++++++ .../copilot/sdk/CliServerManagerTest.java | 27 +++ .../com/github/copilot/sdk/CommandsTest.java | 18 ++ .../github/copilot/sdk/ConfigCloneTest.java | 96 +++++++++ .../copilot/sdk/DataObjectCoverageTest.java | 172 ++++++++++++++++ .../com/github/copilot/sdk/ModelInfoTest.java | 68 +++++++ .../copilot/sdk/RpcHandlerDispatcherTest.java | 48 +++++ .../copilot/sdk/SessionEventParserTest.java | 184 ++++++++++++++++++ .../sdk/SessionRequestBuilderTest.java | 95 +++++++++ .../copilot/sdk/TelemetryConfigTest.java | 77 ++++++++ 10 files changed, 849 insertions(+) create mode 100644 src/test/java/com/github/copilot/sdk/AgentInfoTest.java create mode 100644 src/test/java/com/github/copilot/sdk/DataObjectCoverageTest.java create mode 100644 src/test/java/com/github/copilot/sdk/ModelInfoTest.java create mode 100644 src/test/java/com/github/copilot/sdk/TelemetryConfigTest.java diff --git a/src/test/java/com/github/copilot/sdk/AgentInfoTest.java b/src/test/java/com/github/copilot/sdk/AgentInfoTest.java new file mode 100644 index 000000000..0893773e7 --- /dev/null +++ b/src/test/java/com/github/copilot/sdk/AgentInfoTest.java @@ -0,0 +1,64 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import com.github.copilot.sdk.json.AgentInfo; + +/** + * Unit tests for {@link AgentInfo} getters, setters, and fluent chaining. + */ +class AgentInfoTest { + + @Test + void defaultValuesAreNull() { + var agent = new AgentInfo(); + assertNull(agent.getName()); + assertNull(agent.getDisplayName()); + assertNull(agent.getDescription()); + } + + @Test + void nameGetterSetter() { + var agent = new AgentInfo(); + agent.setName("coder"); + assertEquals("coder", agent.getName()); + } + + @Test + void displayNameGetterSetter() { + var agent = new AgentInfo(); + agent.setDisplayName("Code Assistant"); + assertEquals("Code Assistant", agent.getDisplayName()); + } + + @Test + void descriptionGetterSetter() { + var agent = new AgentInfo(); + agent.setDescription("Helps with coding tasks"); + assertEquals("Helps with coding tasks", agent.getDescription()); + } + + @Test + void fluentChainingReturnsThis() { + var agent = new AgentInfo().setName("coder").setDisplayName("Code Assistant") + .setDescription("Helps with coding tasks"); + + assertEquals("coder", agent.getName()); + assertEquals("Code Assistant", agent.getDisplayName()); + assertEquals("Helps with coding tasks", agent.getDescription()); + } + + @Test + void fluentChainingReturnsSameInstance() { + var agent = new AgentInfo(); + assertSame(agent, agent.setName("test")); + assertSame(agent, agent.setDisplayName("Test")); + assertSame(agent, agent.setDescription("A test agent")); + } +} diff --git a/src/test/java/com/github/copilot/sdk/CliServerManagerTest.java b/src/test/java/com/github/copilot/sdk/CliServerManagerTest.java index f17201583..32257b0a5 100644 --- a/src/test/java/com/github/copilot/sdk/CliServerManagerTest.java +++ b/src/test/java/com/github/copilot/sdk/CliServerManagerTest.java @@ -13,6 +13,7 @@ import org.junit.jupiter.api.Test; import com.github.copilot.sdk.json.CopilotClientOptions; +import com.github.copilot.sdk.json.TelemetryConfig; /** * Unit tests for {@link CliServerManager} covering parseCliUrl, @@ -212,4 +213,30 @@ void startCliServerWithNullCliPath() throws Exception { assertNotNull(e); } } + + @Test + void startCliServerWithTelemetryAllOptions() throws Exception { + // The telemetry env vars are applied before ProcessBuilder.start() + // so even with a nonexistent CLI path, the telemetry code path is exercised + var telemetry = new TelemetryConfig().setOtlpEndpoint("http://localhost:4318").setFilePath("/tmp/telemetry.log") + .setExporterType("otlp-http").setSourceName("test-app").setCaptureContent(true); + var options = new CopilotClientOptions().setCliPath("/nonexistent/copilot").setTelemetry(telemetry) + .setUseStdio(true); + var manager = new CliServerManager(options); + + var ex = assertThrows(IOException.class, () -> manager.startCliServer()); + assertNotNull(ex); + } + + @Test + void startCliServerWithTelemetryCaptureContentFalse() throws Exception { + // Test the false branch of getCaptureContent() + var telemetry = new TelemetryConfig().setCaptureContent(false); + var options = new CopilotClientOptions().setCliPath("/nonexistent/copilot").setTelemetry(telemetry) + .setUseStdio(true); + var manager = new CliServerManager(options); + + var ex = assertThrows(IOException.class, () -> manager.startCliServer()); + assertNotNull(ex); + } } diff --git a/src/test/java/com/github/copilot/sdk/CommandsTest.java b/src/test/java/com/github/copilot/sdk/CommandsTest.java index dad26afbb..baf26b39b 100644 --- a/src/test/java/com/github/copilot/sdk/CommandsTest.java +++ b/src/test/java/com/github/copilot/sdk/CommandsTest.java @@ -135,4 +135,22 @@ void commandWireDefinitionNullDescriptionAllowed() { assertEquals("rollback", wire.getName()); assertNull(wire.getDescription()); } + + @Test + void commandWireDefinitionFluentSetters() { + var wire = new CommandWireDefinition(); + wire.setName("status"); + wire.setDescription("Show deployment status"); + + assertEquals("status", wire.getName()); + assertEquals("Show deployment status", wire.getDescription()); + } + + @Test + void commandWireDefinitionFluentSettersChaining() { + var wire = new CommandWireDefinition().setName("logs").setDescription("View application logs"); + + assertEquals("logs", wire.getName()); + assertEquals("View application logs", wire.getDescription()); + } } diff --git a/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java b/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java index bf4881d5c..f3787705f 100644 --- a/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java +++ b/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java @@ -17,10 +17,13 @@ import com.github.copilot.sdk.events.AbstractSessionEvent; import com.github.copilot.sdk.json.CopilotClientOptions; +import com.github.copilot.sdk.json.InfiniteSessionConfig; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.ModelInfo; import com.github.copilot.sdk.json.ResumeSessionConfig; import com.github.copilot.sdk.json.SessionConfig; +import com.github.copilot.sdk.json.SystemMessageConfig; +import com.github.copilot.sdk.json.TelemetryConfig; class ConfigCloneTest { @@ -193,4 +196,97 @@ void clonePreservesNullFields() { MessageOptions msgClone = msg.clone(); assertNull(msgClone.getMode()); } + + @Test + @SuppressWarnings("deprecation") + void copilotClientOptionsDeprecatedAutoRestart() { + CopilotClientOptions opts = new CopilotClientOptions(); + assertFalse(opts.isAutoRestart()); + opts.setAutoRestart(true); + assertTrue(opts.isAutoRestart()); + } + + @Test + void copilotClientOptionsSetCliArgsNullClearsExisting() { + CopilotClientOptions opts = new CopilotClientOptions(); + opts.setCliArgs(new String[]{"--flag1"}); + assertNotNull(opts.getCliArgs()); + + // Setting null should clear the existing array + opts.setCliArgs(null); + assertNotNull(opts.getCliArgs()); + assertEquals(0, opts.getCliArgs().length); + } + + @Test + void copilotClientOptionsSetEnvironmentNullClearsExisting() { + CopilotClientOptions opts = new CopilotClientOptions(); + opts.setEnvironment(Map.of("KEY", "VALUE")); + assertNotNull(opts.getEnvironment()); + + // Setting null should clear the existing map (clears in-place → returns empty + // map) + opts.setEnvironment(null); + var env = opts.getEnvironment(); + assertTrue(env == null || env.isEmpty()); + } + + @Test + @SuppressWarnings("deprecation") + void copilotClientOptionsDeprecatedGithubToken() { + CopilotClientOptions opts = new CopilotClientOptions(); + opts.setGithubToken("ghp_deprecated_token"); + assertEquals("ghp_deprecated_token", opts.getGithubToken()); + assertEquals("ghp_deprecated_token", opts.getGitHubToken()); + } + + @Test + void copilotClientOptionsSetTelemetry() { + var telemetry = new TelemetryConfig().setOtlpEndpoint("http://localhost:4318"); + var opts = new CopilotClientOptions(); + opts.setTelemetry(telemetry); + assertSame(telemetry, opts.getTelemetry()); + } + + @Test + void copilotClientOptionsSetUseLoggedInUserNull() { + var opts = new CopilotClientOptions(); + opts.setUseLoggedInUser(null); + // null → Boolean.FALSE + assertEquals(Boolean.FALSE, opts.getUseLoggedInUser()); + } + + @Test + void resumeSessionConfigAllSetters() { + var config = new ResumeSessionConfig(); + + var sysMsg = new SystemMessageConfig(); + config.setSystemMessage(sysMsg); + assertSame(sysMsg, config.getSystemMessage()); + + config.setAvailableTools(List.of("bash", "read_file")); + assertEquals(List.of("bash", "read_file"), config.getAvailableTools()); + + config.setExcludedTools(List.of("write_file")); + assertEquals(List.of("write_file"), config.getExcludedTools()); + + config.setReasoningEffort("high"); + assertEquals("high", config.getReasoningEffort()); + + config.setWorkingDirectory("/project/src"); + assertEquals("/project/src", config.getWorkingDirectory()); + + config.setConfigDir("/home/user/.config/copilot"); + assertEquals("/home/user/.config/copilot", config.getConfigDir()); + + config.setSkillDirectories(List.of("/skills/custom")); + assertEquals(List.of("/skills/custom"), config.getSkillDirectories()); + + config.setDisabledSkills(List.of("some-skill")); + assertEquals(List.of("some-skill"), config.getDisabledSkills()); + + var infiniteConfig = new InfiniteSessionConfig().setEnabled(true); + config.setInfiniteSessions(infiniteConfig); + assertSame(infiniteConfig, config.getInfiniteSessions()); + } } diff --git a/src/test/java/com/github/copilot/sdk/DataObjectCoverageTest.java b/src/test/java/com/github/copilot/sdk/DataObjectCoverageTest.java new file mode 100644 index 000000000..203f5faed --- /dev/null +++ b/src/test/java/com/github/copilot/sdk/DataObjectCoverageTest.java @@ -0,0 +1,172 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.github.copilot.sdk.json.GetForegroundSessionResponse; +import com.github.copilot.sdk.json.PermissionRequest; +import com.github.copilot.sdk.json.PermissionRequestResult; +import com.github.copilot.sdk.json.PostToolUseHookInput; +import com.github.copilot.sdk.json.PostToolUseHookOutput; +import com.github.copilot.sdk.json.PreToolUseHookInput; +import com.github.copilot.sdk.json.PreToolUseHookOutput; +import com.github.copilot.sdk.json.SectionOverride; +import com.github.copilot.sdk.json.SetForegroundSessionResponse; +import com.github.copilot.sdk.json.ToolBinaryResult; +import com.github.copilot.sdk.json.ToolResultObject; + +/** + * Unit tests for various data transfer objects and record types that were + * missing coverage, including hook output factory methods, record constructors, + * and getters for hook inputs. + */ +class DataObjectCoverageTest { + + // ===== PreToolUseHookOutput factory methods ===== + + @Test + void preToolUseHookOutputDenyWithReason() { + var output = PreToolUseHookOutput.deny("Security policy violation"); + assertEquals("deny", output.permissionDecision()); + assertEquals("Security policy violation", output.permissionDecisionReason()); + assertNull(output.modifiedArgs()); + } + + @Test + void preToolUseHookOutputAsk() { + var output = PreToolUseHookOutput.ask(); + assertEquals("ask", output.permissionDecision()); + assertNull(output.permissionDecisionReason()); + } + + @Test + void preToolUseHookOutputWithModifiedArgs() { + ObjectNode args = JsonNodeFactory.instance.objectNode(); + args.put("path", "/safe/path"); + + var output = PreToolUseHookOutput.withModifiedArgs("allow", args); + assertEquals("allow", output.permissionDecision()); + assertEquals(args, output.modifiedArgs()); + } + + // ===== PostToolUseHookOutput record ===== + + @Test + void postToolUseHookOutputRecord() { + var output = new PostToolUseHookOutput(null, "Extra context", false); + assertNull(output.modifiedResult()); + assertEquals("Extra context", output.additionalContext()); + assertFalse(output.suppressOutput()); + } + + // ===== ToolBinaryResult record ===== + + @Test + void toolBinaryResultRecord() { + var result = new ToolBinaryResult("base64data==", "image/png", "image", "A chart"); + assertEquals("base64data==", result.data()); + assertEquals("image/png", result.mimeType()); + assertEquals("image", result.type()); + assertEquals("A chart", result.description()); + } + + // ===== GetForegroundSessionResponse record ===== + + @Test + void getForegroundSessionResponseRecord() { + var response = new GetForegroundSessionResponse("session-123", "/home/user/project"); + assertEquals("session-123", response.sessionId()); + assertEquals("/home/user/project", response.workspacePath()); + } + + // ===== SetForegroundSessionResponse record ===== + + @Test + void setForegroundSessionResponseRecord() { + var successResponse = new SetForegroundSessionResponse(true, null); + assertTrue(successResponse.success()); + assertNull(successResponse.error()); + + var errorResponse = new SetForegroundSessionResponse(false, "Session not found"); + assertFalse(errorResponse.success()); + assertEquals("Session not found", errorResponse.error()); + } + + // ===== ToolResultObject factory methods ===== + + @Test + void toolResultObjectErrorWithTextAndError() { + var result = ToolResultObject.error("partial output", "File not found"); + assertEquals("error", result.resultType()); + assertEquals("partial output", result.textResultForLlm()); + assertEquals("File not found", result.error()); + } + + @Test + void toolResultObjectFailure() { + var result = ToolResultObject.failure("Tool unavailable", "Unknown tool"); + assertEquals("failure", result.resultType()); + assertEquals("Tool unavailable", result.textResultForLlm()); + assertEquals("Unknown tool", result.error()); + } + + // ===== PermissionRequest additional setters ===== + + @Test + void permissionRequestSetExtensionData() { + var req = new PermissionRequest(); + req.setExtensionData(java.util.Map.of("key", "value")); + assertEquals("value", req.getExtensionData().get("key")); + } + + // ===== SectionOverride setContent ===== + + @Test + void sectionOverrideSetContent() { + var override = new SectionOverride(); + override.setContent("Custom content"); + assertEquals("Custom content", override.getContent()); + } + + // ===== PreToolUseHookInput getters ===== + + @Test + void preToolUseHookInputGetters() { + var input = new PreToolUseHookInput(); + // Default values + assertEquals(0L, input.getTimestamp()); + assertNull(input.getCwd()); + assertNull(input.getToolArgs()); + } + + // ===== PostToolUseHookInput getters ===== + + @Test + void postToolUseHookInputGetters() { + var input = new PostToolUseHookInput(); + // Default values + assertEquals(0L, input.getTimestamp()); + assertNull(input.getCwd()); + assertNull(input.getToolArgs()); + } + + // ===== PermissionRequestResult setRules ===== + + @Test + void permissionRequestResultSetRules() { + var result = new PermissionRequestResult().setKind("allow"); + var rules = new java.util.ArrayList(); + rules.add("bash:read"); + rules.add("bash:write"); + result.setRules(rules); + assertEquals(2, result.getRules().size()); + assertEquals("bash:read", result.getRules().get(0)); + } +} diff --git a/src/test/java/com/github/copilot/sdk/ModelInfoTest.java b/src/test/java/com/github/copilot/sdk/ModelInfoTest.java new file mode 100644 index 000000000..f36d0c4bd --- /dev/null +++ b/src/test/java/com/github/copilot/sdk/ModelInfoTest.java @@ -0,0 +1,68 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; + +import org.junit.jupiter.api.Test; + +import com.github.copilot.sdk.json.ModelInfo; +import com.github.copilot.sdk.json.ModelSupports; +import com.github.copilot.sdk.json.SessionMetadata; + +/** + * Unit tests for {@link ModelInfo}, {@link ModelSupports}, and + * {@link SessionMetadata} getters and setters. + */ +class ModelInfoTest { + + @Test + void modelSupportsReasoningEffortGetterSetter() { + var supports = new ModelSupports(); + assertFalse(supports.isReasoningEffort()); + + supports.setReasoningEffort(true); + assertTrue(supports.isReasoningEffort()); + } + + @Test + void modelSupportsFluentChaining() { + var supports = new ModelSupports().setVision(true).setReasoningEffort(true); + assertTrue(supports.isVision()); + assertTrue(supports.isReasoningEffort()); + } + + @Test + void modelInfoSupportedReasoningEffortsGetterSetter() { + var model = new ModelInfo(); + assertNull(model.getSupportedReasoningEfforts()); + + model.setSupportedReasoningEfforts(List.of("low", "medium", "high")); + assertEquals(List.of("low", "medium", "high"), model.getSupportedReasoningEfforts()); + } + + @Test + void modelInfoDefaultReasoningEffortGetterSetter() { + var model = new ModelInfo(); + assertNull(model.getDefaultReasoningEffort()); + + model.setDefaultReasoningEffort("medium"); + assertEquals("medium", model.getDefaultReasoningEffort()); + } + + @Test + void sessionMetadataGettersAndSetters() { + var meta = new SessionMetadata(); + assertNull(meta.getStartTime()); + assertNull(meta.getModifiedTime()); + assertNull(meta.getSummary()); + assertFalse(meta.isRemote()); + + meta.setRemote(true); + assertTrue(meta.isRemote()); + } +} diff --git a/src/test/java/com/github/copilot/sdk/RpcHandlerDispatcherTest.java b/src/test/java/com/github/copilot/sdk/RpcHandlerDispatcherTest.java index 79f5d7c7e..315a38b90 100644 --- a/src/test/java/com/github/copilot/sdk/RpcHandlerDispatcherTest.java +++ b/src/test/java/com/github/copilot/sdk/RpcHandlerDispatcherTest.java @@ -542,4 +542,52 @@ void hooksInvokeWithNoHooksRegistered() throws Exception { JsonNode output = response.get("result").get("output"); assertTrue(output == null || output.isNull(), "Output should be null when no hooks registered"); } + + // ===== systemMessage.transform tests ===== + + @Test + void systemMessageTransformWithUnknownSession() throws Exception { + ObjectNode params = MAPPER.createObjectNode(); + params.put("sessionId", "nonexistent"); + params.putObject("sections"); + + invokeHandler("systemMessage.transform", "40", params); + + JsonNode response = readResponse(); + assertNotNull(response.get("error")); + assertEquals(-32602, response.get("error").get("code").asInt()); + } + + @Test + void systemMessageTransformWithNullSessionId() throws Exception { + ObjectNode params = MAPPER.createObjectNode(); + // sessionId omitted → null → session lookup returns null → error + params.putObject("sections"); + + invokeHandler("systemMessage.transform", "41", params); + + JsonNode response = readResponse(); + assertNotNull(response.get("error")); + assertEquals(-32602, response.get("error").get("code").asInt()); + } + + @Test + void systemMessageTransformWithKnownSessionNoCallbacks() throws Exception { + // Session without transform callbacks returns the sections unchanged + createSession("s1"); + + ObjectNode params = MAPPER.createObjectNode(); + params.put("sessionId", "s1"); + ObjectNode sections = params.putObject("sections"); + ObjectNode sectionData = sections.putObject("identity"); + sectionData.put("content", "Original content"); + + invokeHandler("systemMessage.transform", "42", params); + + JsonNode response = readResponse(); + assertNotNull(response.get("result")); + JsonNode resultSections = response.get("result").get("sections"); + assertNotNull(resultSections); + assertEquals("Original content", resultSections.get("identity").get("content").asText()); + } } diff --git a/src/test/java/com/github/copilot/sdk/SessionEventParserTest.java b/src/test/java/com/github/copilot/sdk/SessionEventParserTest.java index 5898d5301..4a63bb243 100644 --- a/src/test/java/com/github/copilot/sdk/SessionEventParserTest.java +++ b/src/test/java/com/github/copilot/sdk/SessionEventParserTest.java @@ -2385,4 +2385,188 @@ void testParseSystemNotificationEvent() throws Exception { assertNotNull(event.getData()); assertTrue(event.getData().content().contains("Agent completed")); } + + @Test + void testParseCapabilitiesChangedEvent() throws Exception { + String json = """ + { + "type": "capabilities.changed", + "data": { + "ui": { + "elicitation": true + } + } + } + """; + + AbstractSessionEvent event = parseJson(json); + assertNotNull(event); + assertInstanceOf(CapabilitiesChangedEvent.class, event); + assertEquals("capabilities.changed", event.getType()); + + var castedEvent = (CapabilitiesChangedEvent) event; + assertNotNull(castedEvent.getData()); + assertNotNull(castedEvent.getData().ui()); + assertTrue(castedEvent.getData().ui().elicitation()); + + // Verify setData round-trip + var newData = new CapabilitiesChangedEvent.CapabilitiesChangedData( + new CapabilitiesChangedEvent.CapabilitiesChangedUi(false)); + castedEvent.setData(newData); + assertFalse(castedEvent.getData().ui().elicitation()); + } + + @Test + void testParseCommandExecuteEvent() throws Exception { + String json = """ + { + "type": "command.execute", + "data": { + "requestId": "req-001", + "command": "/deploy production", + "commandName": "deploy", + "args": "production" + } + } + """; + + AbstractSessionEvent event = parseJson(json); + assertNotNull(event); + assertInstanceOf(CommandExecuteEvent.class, event); + assertEquals("command.execute", event.getType()); + + var castedEvent = (CommandExecuteEvent) event; + assertNotNull(castedEvent.getData()); + assertEquals("req-001", castedEvent.getData().requestId()); + assertEquals("/deploy production", castedEvent.getData().command()); + assertEquals("deploy", castedEvent.getData().commandName()); + assertEquals("production", castedEvent.getData().args()); + + // Verify setData round-trip + castedEvent.setData(new CommandExecuteEvent.CommandExecuteData("req-002", "/rollback", "rollback", null)); + assertEquals("req-002", castedEvent.getData().requestId()); + } + + @Test + void testParseElicitationRequestedEvent() throws Exception { + String json = """ + { + "type": "elicitation.requested", + "data": { + "requestId": "elix-001", + "toolCallId": "tc-123", + "elicitationSource": "mcp_tool", + "message": "Please provide your name", + "mode": "form", + "requestedSchema": { + "type": "object", + "properties": { + "name": {"type": "string"} + }, + "required": ["name"] + }, + "url": null + } + } + """; + + AbstractSessionEvent event = parseJson(json); + assertNotNull(event); + assertInstanceOf(ElicitationRequestedEvent.class, event); + assertEquals("elicitation.requested", event.getType()); + + var castedEvent = (ElicitationRequestedEvent) event; + assertNotNull(castedEvent.getData()); + assertEquals("elix-001", castedEvent.getData().requestId()); + assertEquals("tc-123", castedEvent.getData().toolCallId()); + assertEquals("mcp_tool", castedEvent.getData().elicitationSource()); + assertEquals("Please provide your name", castedEvent.getData().message()); + assertEquals("form", castedEvent.getData().mode()); + assertNotNull(castedEvent.getData().requestedSchema()); + assertEquals("object", castedEvent.getData().requestedSchema().type()); + assertNotNull(castedEvent.getData().requestedSchema().properties()); + assertNotNull(castedEvent.getData().requestedSchema().required()); + assertTrue(castedEvent.getData().requestedSchema().required().contains("name")); + + // Verify setData round-trip + castedEvent.setData(new ElicitationRequestedEvent.ElicitationRequestedData("elix-002", null, null, "Enter URL", + "url", null, "https://example.com")); + assertEquals("elix-002", castedEvent.getData().requestId()); + assertEquals("url", castedEvent.getData().mode()); + } + + @Test + void testParseSessionContextChangedEvent() throws Exception { + String json = """ + { + "type": "session.context_changed", + "data": { + "cwd": "/home/user/project", + "gitRoot": "/home/user/project", + "repository": "my-repo", + "branch": "main" + } + } + """; + + AbstractSessionEvent event = parseJson(json); + assertNotNull(event); + assertInstanceOf(SessionContextChangedEvent.class, event); + assertEquals("session.context_changed", event.getType()); + + var castedEvent = (SessionContextChangedEvent) event; + assertNotNull(castedEvent.getData()); + assertEquals("/home/user/project", castedEvent.getData().getCwd()); + + // Verify setData round-trip + castedEvent.setData(null); + assertNull(castedEvent.getData()); + } + + @Test + void testParseSessionTaskCompleteEvent() throws Exception { + String json = """ + { + "type": "session.task_complete", + "data": { + "summary": "Task completed successfully" + } + } + """; + + AbstractSessionEvent event = parseJson(json); + assertNotNull(event); + assertInstanceOf(SessionTaskCompleteEvent.class, event); + assertEquals("session.task_complete", event.getType()); + + var castedEvent = (SessionTaskCompleteEvent) event; + assertNotNull(castedEvent.getData()); + assertEquals("Task completed successfully", castedEvent.getData().summary()); + + // Verify setData round-trip + castedEvent.setData(new SessionTaskCompleteEvent.SessionTaskCompleteData("New summary")); + assertEquals("New summary", castedEvent.getData().summary()); + } + + @Test + void testParseSubagentDeselectedEvent() throws Exception { + String json = """ + { + "type": "subagent.deselected", + "data": {} + } + """; + + AbstractSessionEvent event = parseJson(json); + assertNotNull(event); + assertInstanceOf(SubagentDeselectedEvent.class, event); + assertEquals("subagent.deselected", event.getType()); + + var castedEvent = (SubagentDeselectedEvent) event; + assertNotNull(castedEvent.getData()); + + // Verify setData round-trip + castedEvent.setData(new SubagentDeselectedEvent.SubagentDeselectedData()); + assertNotNull(castedEvent.getData()); + } } diff --git a/src/test/java/com/github/copilot/sdk/SessionRequestBuilderTest.java b/src/test/java/com/github/copilot/sdk/SessionRequestBuilderTest.java index 1a64b7534..75457583e 100644 --- a/src/test/java/com/github/copilot/sdk/SessionRequestBuilderTest.java +++ b/src/test/java/com/github/copilot/sdk/SessionRequestBuilderTest.java @@ -13,6 +13,9 @@ import org.junit.jupiter.api.Test; import com.github.copilot.sdk.json.CreateSessionRequest; +import com.github.copilot.sdk.json.ElicitationHandler; +import com.github.copilot.sdk.json.ElicitationResult; +import com.github.copilot.sdk.json.ElicitationResultAction; import com.github.copilot.sdk.json.ResumeSessionConfig; import com.github.copilot.sdk.json.ResumeSessionRequest; import com.github.copilot.sdk.json.SessionConfig; @@ -305,4 +308,96 @@ void extractTransformCallbacks_customizeModeWithTransform_extractsCallbacks() { assertEquals(com.github.copilot.sdk.json.SectionOverrideAction.TRANSFORM, wireSection.getAction()); assertNull(wireSection.getTransform()); } + + @Test + @SuppressWarnings("deprecation") + void buildCreateRequestWithSessionId_usesProvidedSessionId() { + var config = new SessionConfig(); + config.setSessionId("my-session-id"); + + // The deprecated single-arg overload uses the sessionId from config when set + CreateSessionRequest request = SessionRequestBuilder.buildCreateRequest(config); + + assertEquals("my-session-id", request.getSessionId()); + } + + @Test + void configureSessionWithNullConfig_returnsEarly() { + // configureSession with null config should return without error + CopilotSession session = new CopilotSession("session-1", null); + // Covers the null config early-return branch (L219-220) + assertDoesNotThrow(() -> SessionRequestBuilder.configureSession(session, (SessionConfig) null)); + } + + @Test + void configureSessionWithCommands_registersCommands() { + CopilotSession session = new CopilotSession("session-1", null); + + var cmd = new com.github.copilot.sdk.json.CommandDefinition().setName("deploy") + .setHandler(ctx -> CompletableFuture.completedFuture(null)); + var config = new SessionConfig().setCommands(List.of(cmd)); + + // Covers config.getCommands() != null branch (L235-236) + SessionRequestBuilder.configureSession(session, config); + // If no exception thrown, the branch was covered + } + + @Test + void configureSessionWithElicitationHandler_registersHandler() { + CopilotSession session = new CopilotSession("session-1", null); + + ElicitationHandler handler = (context) -> CompletableFuture + .completedFuture(new ElicitationResult().setAction(ElicitationResultAction.CANCEL)); + var config = new SessionConfig().setOnElicitationRequest(handler); + + // Covers config.getOnElicitationRequest() != null branch (L238-239) + SessionRequestBuilder.configureSession(session, config); + } + + @Test + void configureSessionWithOnEvent_registersEventHandler() { + CopilotSession session = new CopilotSession("session-1", null); + + var config = new SessionConfig().setOnEvent(event -> { + }); + + // Covers config.getOnEvent() != null branch (L241-242) + SessionRequestBuilder.configureSession(session, config); + } + + @Test + void configureResumedSessionWithCommands_registersCommands() { + CopilotSession session = new CopilotSession("session-1", null); + + var cmd = new com.github.copilot.sdk.json.CommandDefinition().setName("rollback") + .setHandler(ctx -> CompletableFuture.completedFuture(null)); + var config = new ResumeSessionConfig().setCommands(List.of(cmd)); + + // Covers ResumeSessionConfig.getCommands() != null branch (L271-272) + SessionRequestBuilder.configureSession(session, config); + } + + @Test + void configureResumedSessionWithElicitationHandler_registersHandler() { + CopilotSession session = new CopilotSession("session-1", null); + + ElicitationHandler handler = (context) -> CompletableFuture + .completedFuture(new ElicitationResult().setAction(ElicitationResultAction.CANCEL)); + var config = new ResumeSessionConfig().setOnElicitationRequest(handler); + + // Covers ResumeSessionConfig.getOnElicitationRequest() != null branch + // (L274-275) + SessionRequestBuilder.configureSession(session, config); + } + + @Test + void configureResumedSessionWithOnEvent_registersEventHandler() { + CopilotSession session = new CopilotSession("session-1", null); + + var config = new ResumeSessionConfig().setOnEvent(event -> { + }); + + // Covers ResumeSessionConfig.getOnEvent() != null branch (L277-278) + SessionRequestBuilder.configureSession(session, config); + } } diff --git a/src/test/java/com/github/copilot/sdk/TelemetryConfigTest.java b/src/test/java/com/github/copilot/sdk/TelemetryConfigTest.java new file mode 100644 index 000000000..99b360d2d --- /dev/null +++ b/src/test/java/com/github/copilot/sdk/TelemetryConfigTest.java @@ -0,0 +1,77 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import com.github.copilot.sdk.json.TelemetryConfig; + +/** + * Unit tests for {@link TelemetryConfig} getters, setters, and fluent chaining. + */ +class TelemetryConfigTest { + + @Test + void defaultValuesAreNull() { + var config = new TelemetryConfig(); + assertNull(config.getOtlpEndpoint()); + assertNull(config.getFilePath()); + assertNull(config.getExporterType()); + assertNull(config.getSourceName()); + assertNull(config.getCaptureContent()); + } + + @Test + void otlpEndpointGetterSetter() { + var config = new TelemetryConfig(); + config.setOtlpEndpoint("http://localhost:4318"); + assertEquals("http://localhost:4318", config.getOtlpEndpoint()); + } + + @Test + void filePathGetterSetter() { + var config = new TelemetryConfig(); + config.setFilePath("/tmp/telemetry.log"); + assertEquals("/tmp/telemetry.log", config.getFilePath()); + } + + @Test + void exporterTypeGetterSetter() { + var config = new TelemetryConfig(); + config.setExporterType("otlp-http"); + assertEquals("otlp-http", config.getExporterType()); + } + + @Test + void sourceNameGetterSetter() { + var config = new TelemetryConfig(); + config.setSourceName("my-app"); + assertEquals("my-app", config.getSourceName()); + } + + @Test + void captureContentGetterSetter() { + var config = new TelemetryConfig(); + config.setCaptureContent(true); + assertTrue(config.getCaptureContent()); + + config.setCaptureContent(false); + assertFalse(config.getCaptureContent()); + } + + @Test + void fluentChainingReturnsThis() { + var config = new TelemetryConfig().setOtlpEndpoint("http://localhost:4318").setFilePath("/tmp/spans.json") + .setExporterType("file").setSourceName("sdk-test").setCaptureContent(true); + + assertEquals("http://localhost:4318", config.getOtlpEndpoint()); + assertEquals("/tmp/spans.json", config.getFilePath()); + assertEquals("file", config.getExporterType()); + assertEquals("sdk-test", config.getSourceName()); + assertTrue(config.getCaptureContent()); + } +} From 2b24c6f639e1f51dd6228b6ef8ea4360f111ca41 Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Mon, 6 Apr 2026 18:30:36 -0400 Subject: [PATCH 50/80] Update Mockito to 5.23.0 for Java 25 support Mockito 5.17.0 bundled ByteBuddy 1.15.11 which does not support Java 25 class files, causing SchedulerShutdownRaceTest and ZeroTimeoutContractTest to fail with 'Mockito cannot mock this class'. - Upgrade mockito-core from 5.17.0 to 5.23.0 (includes ByteBuddy 1.17.5+) - Add JDK 21+ profile that passes -XX:+EnableDynamicAgentLoading to Surefire, allowing Mockito/ByteBuddy to attach at runtime (JEP 451) - Use a default-empty surefire.jvm.args property so JDK 17-20 are unaffected by the flag Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pom.xml | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 45404d99a..43e36ec4d 100644 --- a/pom.xml +++ b/pom.xml @@ -51,6 +51,8 @@ ${copilot.sdk.clone.dir}/test false + + @@ -89,7 +91,7 @@ org.mockito mockito-core - 5.17.0 + 5.23.0 test @@ -245,8 +247,8 @@ maven-surefire-plugin 3.5.4 - - ${testExecutionAgentArgs} + + ${testExecutionAgentArgs} ${surefire.jvm.args} ${copilot.tests.dir} ${copilot.sdk.clone.dir} @@ -543,6 +545,18 @@ + + + jdk21+ + + [21,) + + + -XX:+EnableDynamicAgentLoading + + skip-test-harness From cce87cb1caf9701753bf64ee25be76cc3156d224 Mon Sep 17 00:00:00 2001 From: brunoborges <129743+brunoborges@users.noreply.github.com> Date: Mon, 6 Apr 2026 22:53:38 +0000 Subject: [PATCH 51/80] Update JaCoCo coverage badge --- .github/badges/jacoco.svg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/badges/jacoco.svg b/.github/badges/jacoco.svg index a310734d0..f1a7c5eb3 100644 --- a/.github/badges/jacoco.svg +++ b/.github/badges/jacoco.svg @@ -6,13 +6,13 @@ - + coverage coverage - 78.3% - 78.3% + 84.4% + 84.4% From 00a3aa58630e142c23b7c85a80e0caa91a2dcc79 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 7 Apr 2026 09:05:43 +0000 Subject: [PATCH 52/80] Initial plan From 7e440159b95bda22d9cee3239f96befe5cf848eb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 7 Apr 2026 09:28:30 +0000 Subject: [PATCH 53/80] Update .lastmerge to c3fa6cbfb83d4a20b7912b1a17013d48f5a277a1 Co-authored-by: edburns <75821+edburns@users.noreply.github.com> --- .lastmerge | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.lastmerge b/.lastmerge index 0d0067b5b..83feb636c 100644 --- a/.lastmerge +++ b/.lastmerge @@ -1 +1 @@ -f7fd7577109d64e261456b16c49baa56258eae4e +c3fa6cbfb83d4a20b7912b1a17013d48f5a277a1 From 1508b9f323dec865eadef9fb53c7512bbdda1b80 Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Tue, 7 Apr 2026 09:37:25 -0400 Subject: [PATCH 54/80] Update documentation for PR #52 upstream sync features Add coverage for slash commands, elicitation (UI dialogs), session capabilities, SessionUiApi, and getSessionMetadata across: - CHANGELOG.md: Unreleased section with Added/Fixed entries - documentation.md: event types, SessionConfig reference, resume options - advanced.md: table of contents entries for new sections - site.xml: navigation menu items Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CHANGELOG.md | 22 +++++++++++++++++++++- src/site/markdown/advanced.md | 7 +++++++ src/site/markdown/documentation.md | 17 +++++++++++++++++ src/site/site.xml | 3 +++ 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e306db097..f5050a3d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,27 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Unreleased] -> **Upstream sync:** [`github/copilot-sdk@4088739`](https://github.com/github/copilot-sdk/commit/40887393a9e687dacc141a645799441b0313ff15) +> **Upstream sync:** [`github/copilot-sdk@f7fd757`](https://github.com/github/copilot-sdk/commit/f7fd7577109d64e261456b16c49baa56258eae4e) + +### Added + +- Slash commands — register `/command` handlers invoked from the CLI TUI via `SessionConfig.setCommands()` (upstream: [`f7fd757`](https://github.com/github/copilot-sdk/commit/f7fd757)) +- `CommandDefinition`, `CommandContext`, `CommandHandler`, `CommandWireDefinition` — types for defining and handling slash commands +- `CommandExecuteEvent` — event dispatched when a registered slash command is executed +- Elicitation (UI dialogs) — incoming handler via `SessionConfig.setOnElicitationRequest()` and outgoing convenience methods via `session.getUi()` (upstream: [`f7fd757`](https://github.com/github/copilot-sdk/commit/f7fd757)) +- `ElicitationContext`, `ElicitationHandler`, `ElicitationParams`, `ElicitationResult`, `ElicitationResultAction`, `ElicitationSchema`, `InputOptions` — types for elicitation +- `ElicitationRequestedEvent` — event dispatched when an elicitation request is received +- `SessionUiApi` — convenience API on `session.getUi()` for `confirm()`, `select()`, `input()`, and `elicitation()` calls +- `SessionCapabilities` and `SessionUiCapabilities` — session capability reporting populated from create/resume response +- `CapabilitiesChangedEvent` — event dispatched when session capabilities are updated +- `CopilotClient.getSessionMetadata(String)` — O(1) session lookup by ID +- `GetSessionMetadataResponse` — response type for `getSessionMetadata` + +### Fixed + +- Permission events already resolved by a pre-hook now short-circuit before invoking the client-side handler +- `SessionUiApi` Javadoc now uses valid Java null-check syntax instead of `?.` +- README updated to say "GitHub Copilot CLI 1.0.17" instead of "GitHub Copilot 1.0.17" ## [0.2.1-java.1] - 2026-04-02 diff --git a/src/site/markdown/advanced.md b/src/site/markdown/advanced.md index 598acc2f7..5ae5c8f94 100644 --- a/src/site/markdown/advanced.md +++ b/src/site/markdown/advanced.md @@ -47,6 +47,13 @@ This guide covers advanced scenarios for extending and customizing your Copilot - [Custom Event Error Handler](#Custom_Event_Error_Handler) - [Event Error Policy](#Event_Error_Policy) - [OpenTelemetry](#OpenTelemetry) +- [Slash Commands](#Slash_Commands) + - [Registering Commands](#Registering_Commands) +- [Elicitation (UI Dialogs)](#Elicitation_UI_Dialogs) + - [Incoming Elicitation Handler](#Incoming_Elicitation_Handler) + - [Session Capabilities](#Session_Capabilities) + - [Outgoing Elicitation via session.getUi()](#Outgoing_Elicitation_via_session.getUi) +- [Getting Session Metadata by ID](#Getting_Session_Metadata_by_ID) --- diff --git a/src/site/markdown/documentation.md b/src/site/markdown/documentation.md index 8a9f919ac..a96f66698 100644 --- a/src/site/markdown/documentation.md +++ b/src/site/markdown/documentation.md @@ -245,6 +245,19 @@ The SDK supports event types organized by category. All events extend `AbstractS |-------|-------------|-------------| | `CommandQueuedEvent` | `command.queued` | A command was queued for execution | | `CommandCompletedEvent` | `command.completed` | A queued command completed | +| `CommandExecuteEvent` | `command.execute` | A registered slash command was dispatched for execution | + +### Elicitation Events + +| Event | Type String | Description | +|-------|-------------|-------------| +| `ElicitationRequestedEvent` | `elicitation.requested` | An elicitation (UI dialog) request was received | + +### Capability Events + +| Event | Type String | Description | +|-------|-------------|-------------| +| `CapabilitiesChangedEvent` | `capabilities.changed` | Session capabilities were updated | ### Plan Mode Events @@ -633,6 +646,8 @@ When resuming a session, you can optionally reconfigure many settings. This is u | `skillDirectories` | Directories to load skills from | | `disabledSkills` | Skills to disable | | `infiniteSessions` | Configure infinite session behavior | +| `commands` | Slash command definitions for the resumed session | +| `onElicitationRequest` | Handler for incoming elicitation requests | | `disableResume` | When `true`, resumes without emitting a `session.resume` event | | `onEvent` | Event handler registered before session resumption | @@ -691,6 +706,8 @@ Complete list of all `SessionConfig` options for `createSession()`: | `skillDirectories` | List<String> | Directories to load skills from | [Skills](advanced.html#Skills_Configuration) | | `disabledSkills` | List<String> | Skills to disable by name | [Skills](advanced.html#Skills_Configuration) | | `configDir` | String | Custom configuration directory | [Config Dir](advanced.html#Custom_Configuration_Directory) | +| `commands` | List<CommandDefinition> | Slash command definitions | [Slash Commands](advanced.html#Slash_Commands) | +| `onElicitationRequest` | ElicitationHandler | Handler for incoming elicitation requests | [Elicitation](advanced.html#Elicitation_UI_Dialogs) | | `onEvent` | Consumer<AbstractSessionEvent> | Event handler registered before session creation | [Early Event Registration](advanced.html#Early_Event_Registration) | ### Cloning SessionConfig diff --git a/src/site/site.xml b/src/site/site.xml index f89ebe076..d012c0335 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -59,6 +59,9 @@ + + + From 04d03a798acc69044aa5e6377334fe34e0cc952a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 7 Apr 2026 14:13:12 +0000 Subject: [PATCH 55/80] docs: update version references to 0.2.2-java.1 --- CHANGELOG.md | 19 ++++++++++++++----- README.md | 4 ++-- src/site/markdown/cookbook/error-handling.md | 14 +++++++------- .../markdown/cookbook/managing-local-files.md | 4 ++-- .../markdown/cookbook/multiple-sessions.md | 4 ++-- .../markdown/cookbook/persisting-sessions.md | 6 +++--- .../markdown/cookbook/pr-visualization.md | 2 +- 7 files changed, 31 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5050a3d2..38f6e6589 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Unreleased] -> **Upstream sync:** [`github/copilot-sdk@f7fd757`](https://github.com/github/copilot-sdk/commit/f7fd7577109d64e261456b16c49baa56258eae4e) +> **Upstream sync:** [`github/copilot-sdk@c3fa6cb`](https://github.com/github/copilot-sdk/commit/c3fa6cbfb83d4a20b7912b1a17013d48f5a277a1) +## [0.2.2-java.1] - 2026-04-07 + +> **Upstream sync:** [`github/copilot-sdk@c3fa6cb`](https://github.com/github/copilot-sdk/commit/c3fa6cbfb83d4a20b7912b1a17013d48f5a277a1) ### Added - Slash commands — register `/command` handlers invoked from the CLI TUI via `SessionConfig.setCommands()` (upstream: [`f7fd757`](https://github.com/github/copilot-sdk/commit/f7fd757)) @@ -485,16 +488,22 @@ New types: `GetForegroundSessionResponse`, `SetForegroundSessionResponse` - Pre-commit hook for Spotless code formatting - Comprehensive API documentation -[Unreleased]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.1...HEAD +[Unreleased]: https://github.com/github/copilot-sdk-java/compare/v0.2.2-java.1...HEAD +[0.2.2-java.1]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.1...v0.2.2-java.1 +[Unreleased]: https://github.com/github/copilot-sdk-java/compare/v0.2.2-java.1...HEAD +[0.2.2-java.1]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.1...v0.2.2-java.1 [0.2.1-java.1]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.0...v0.2.1-java.1 -[Unreleased]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.1...HEAD +[Unreleased]: https://github.com/github/copilot-sdk-java/compare/v0.2.2-java.1...HEAD +[0.2.2-java.1]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.1...v0.2.2-java.1 [0.2.1-java.1]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.0...v0.2.1-java.1 [0.2.1-java.0]: https://github.com/github/copilot-sdk-java/compare/v0.1.32-java.0...v0.2.1-java.0 -[Unreleased]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.1...HEAD +[Unreleased]: https://github.com/github/copilot-sdk-java/compare/v0.2.2-java.1...HEAD +[0.2.2-java.1]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.1...v0.2.2-java.1 [0.2.1-java.1]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.0...v0.2.1-java.1 [0.2.1-java.0]: https://github.com/github/copilot-sdk-java/compare/v0.1.32-java.0...v0.2.1-java.0 [0.1.32-java.0]: https://github.com/github/copilot-sdk-java/compare/v1.0.11...v0.1.32-java.0 -[Unreleased]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.1...HEAD +[Unreleased]: https://github.com/github/copilot-sdk-java/compare/v0.2.2-java.1...HEAD +[0.2.2-java.1]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.1...v0.2.2-java.1 [0.2.1-java.1]: https://github.com/github/copilot-sdk-java/compare/v0.2.1-java.0...v0.2.1-java.1 [0.2.1-java.0]: https://github.com/github/copilot-sdk-java/compare/v0.1.32-java.0...v0.2.1-java.0 [0.1.32-java.0]: https://github.com/github/copilot-sdk-java/compare/v1.0.11...v0.1.32-java.0 diff --git a/README.md b/README.md index 677389c6e..539a33895 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Java SDK for programmatic control of GitHub Copilot CLI, enabling you to build A com.github copilot-sdk-java - 0.2.1-java.1 + 0.2.2-java.1 ``` @@ -60,7 +60,7 @@ Snapshot builds of the next development version are published to Maven Central S ### Gradle ```groovy -implementation 'com.github:copilot-sdk-java:0.2.1-java.1' +implementation 'com.github:copilot-sdk-java:0.2.2-java.1' ``` ## Quick Start diff --git a/src/site/markdown/cookbook/error-handling.md b/src/site/markdown/cookbook/error-handling.md index 5ee5ef2ca..4240dc1ff 100644 --- a/src/site/markdown/cookbook/error-handling.md +++ b/src/site/markdown/cookbook/error-handling.md @@ -30,7 +30,7 @@ jbang BasicErrorHandling.java **Code:** ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.1 +//DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; @@ -64,7 +64,7 @@ public class BasicErrorHandling { ## Handling specific error types ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.1 +//DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; import java.util.concurrent.ExecutionException; @@ -99,7 +99,7 @@ public class SpecificErrorHandling { ## Timeout handling ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.1 +//DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotSession; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; @@ -130,7 +130,7 @@ public class TimeoutHandling { ## Aborting a request ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.1 +//DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotSession; import com.github.copilot.sdk.json.MessageOptions; import java.util.concurrent.Executors; @@ -162,7 +162,7 @@ public class AbortRequest { ## Graceful shutdown ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.1 +//DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; public class GracefulShutdown { @@ -192,7 +192,7 @@ public class GracefulShutdown { ## Try-with-resources pattern ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.1 +//DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; @@ -224,7 +224,7 @@ public class TryWithResources { ## Handling tool errors ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.1 +//DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; diff --git a/src/site/markdown/cookbook/managing-local-files.md b/src/site/markdown/cookbook/managing-local-files.md index aa9ba23bc..9535772b2 100644 --- a/src/site/markdown/cookbook/managing-local-files.md +++ b/src/site/markdown/cookbook/managing-local-files.md @@ -34,7 +34,7 @@ jbang ManagingLocalFiles.java **Code:** ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.1 +//DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.events.SessionIdleEvent; @@ -161,7 +161,7 @@ session.send(new MessageOptions().setPrompt(prompt)); ## Interactive file organization ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.1 +//DEPS com.github:copilot-sdk-java:0.2.2-java.1 import java.io.BufferedReader; import java.io.InputStreamReader; diff --git a/src/site/markdown/cookbook/multiple-sessions.md b/src/site/markdown/cookbook/multiple-sessions.md index fe5c2f0d9..776b6db6d 100644 --- a/src/site/markdown/cookbook/multiple-sessions.md +++ b/src/site/markdown/cookbook/multiple-sessions.md @@ -30,7 +30,7 @@ jbang MultipleSessions.java **Code:** ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.1 +//DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; @@ -123,7 +123,7 @@ try { ## Managing session lifecycle with CompletableFuture ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.1 +//DEPS com.github:copilot-sdk-java:0.2.2-java.1 import java.util.concurrent.CompletableFuture; import java.util.List; diff --git a/src/site/markdown/cookbook/persisting-sessions.md b/src/site/markdown/cookbook/persisting-sessions.md index e3fd11b13..e653b8a6a 100644 --- a/src/site/markdown/cookbook/persisting-sessions.md +++ b/src/site/markdown/cookbook/persisting-sessions.md @@ -30,7 +30,7 @@ jbang PersistingSessions.java **Code:** ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.1 +//DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; @@ -127,7 +127,7 @@ public class DeleteSession { ## Getting session history ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.1 +//DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.events.UserMessageEvent; @@ -162,7 +162,7 @@ public class SessionHistory { ## Complete example with session management ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.1 +//DEPS com.github:copilot-sdk-java:0.2.2-java.1 import java.util.Scanner; public class SessionManager { diff --git a/src/site/markdown/cookbook/pr-visualization.md b/src/site/markdown/cookbook/pr-visualization.md index dbd240a40..ad2939842 100644 --- a/src/site/markdown/cookbook/pr-visualization.md +++ b/src/site/markdown/cookbook/pr-visualization.md @@ -34,7 +34,7 @@ jbang PRVisualization.java github/copilot-sdk ## Full example: PRVisualization.java ```java -//DEPS com.github:copilot-sdk-java:0.2.1-java.1 +//DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.events.ToolExecutionStartEvent; From a86edb2891b5784c271f787c29ea368b12734f61 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 7 Apr 2026 14:13:34 +0000 Subject: [PATCH 56/80] [maven-release-plugin] prepare release v0.2.2-java.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 43e36ec4d..8e3e7e1df 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.github copilot-sdk-java - 0.2.2-java.1-SNAPSHOT + 0.2.2-java.1 jar GitHub Copilot SDK :: Java @@ -33,7 +33,7 @@ scm:git:https://github.com/github/copilot-sdk-java.git scm:git:https://github.com/github/copilot-sdk-java.git https://github.com/github/copilot-sdk-java - HEAD + v0.2.2-java.1 From 0704bc5b44d7802aa1fe31a62f98c7e0dd50aef7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 7 Apr 2026 14:13:38 +0000 Subject: [PATCH 57/80] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8e3e7e1df..b61c36166 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.github copilot-sdk-java - 0.2.2-java.1 + 0.2.3-java.1-SNAPSHOT jar GitHub Copilot SDK :: Java @@ -33,7 +33,7 @@ scm:git:https://github.com/github/copilot-sdk-java.git scm:git:https://github.com/github/copilot-sdk-java.git https://github.com/github/copilot-sdk-java - v0.2.2-java.1 + HEAD From a1c3bdd42b5ffdbde680563a63f3b3afb65be391 Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Tue, 7 Apr 2026 10:18:01 -0400 Subject: [PATCH 58/80] Update GitHub release title to 'GitHub Copilot SDK for Java' Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/publish-maven.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-maven.yml b/.github/workflows/publish-maven.yml index a7bb58f01..f2960a756 100644 --- a/.github/workflows/publish-maven.yml +++ b/.github/workflows/publish-maven.yml @@ -206,7 +206,7 @@ jobs: # Build the gh release command GH_ARGS=("${CURRENT_TAG}") - GH_ARGS+=("--title" "Copilot Java SDK ${VERSION}") + GH_ARGS+=("--title" "GitHub Copilot SDK for Java ${VERSION}") GH_ARGS+=("--notes" "${RELEASE_NOTES}") GH_ARGS+=("--generate-notes") From 9079e047a279a9a34aba3bc6fcb3a5b2db6de92f Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Tue, 7 Apr 2026 10:25:54 -0400 Subject: [PATCH 59/80] Update disclaimer from pre-GA to public preview Replace 'Disclaimer' warnings with 'Public Preview' notices across README, site docs, release notes template, and HTML version selector. Drop 'Use at your own risk' language and tone down to reflect public preview status. Fix 'SDKS' typo to 'SDKs'. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/templates/index.html | 4 ++-- .github/workflows/notes.template | 2 +- README.md | 2 +- instructions/copilot-sdk-java.instructions.md | 2 +- src/site/markdown/index.md | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/templates/index.html b/.github/templates/index.html index 9af01dded..85b96106f 100644 --- a/.github/templates/index.html +++ b/.github/templates/index.html @@ -65,8 +65,8 @@

Available Versions

-
- ⚠️ Disclaimer: This is the official Java SDK for GitHub Copilot. This repository treats the official .NET and nodejs SDKs for GitHub Copilot as reference implementations. These SDKS are all officially supported as GitHub open source projects. The Java implementation follows the backward compatibility guarantees offered by the reference implementations. As such this implementation may introduce breaking changes, according to the policy declared by the reference implementations. Use at your own risk. +
+ ℹ️ Public Preview: This is the official Java SDK for GitHub Copilot. This repository treats the official .NET and nodejs SDKs for GitHub Copilot as reference implementations. These SDKs are all officially supported as GitHub open source projects. The Java implementation follows the backward compatibility guarantees offered by the reference implementations. While in public preview, minor breaking changes may still occur between releases.
diff --git a/.github/workflows/notes.template b/.github/workflows/notes.template index 0fd7af642..0199452eb 100644 --- a/.github/workflows/notes.template +++ b/.github/workflows/notes.template @@ -1,6 +1,6 @@ # Installation -⚠️ **Disclaimer:** This is the official Java SDK for GitHub Copilot. This repository treats the official .NET and nodejs SDKs for GitHub Copilot as reference implementations. These SDKS are all officially supported as GitHub open source projects. The Java implementation follows the backward compatibility guarantees offered by the reference implementations. As such this implementation may introduce breaking changes, according to the policy declared by the reference implementations. Use at your own risk. +ℹ️ **Public Preview:** This is the official Java SDK for GitHub Copilot. This repository treats the official .NET and nodejs SDKs for GitHub Copilot as reference implementations. These SDKs are all officially supported as GitHub open source projects. The Java implementation follows the backward compatibility guarantees offered by the reference implementations. While in public preview, minor breaking changes may still occur between releases. ⚠️ **Artifact versioning plan:** Releases of this implementation track releases of the reference implementation. For each release of the reference implementation, there may follow a corresponding relase of this implementation with the same number as the reference implementation. Release identifiers of the reference implementation are in the form `vMaj.Min.Micro`. For example v0.1.32. The corresponding maven version for the release will be `Maj.Min.Micro-java.N`, where `Maj`, `Min` and `Micro` are the corresponding numbers for the reference impementation release, and `N` is a monotonically increasing sequence number starting with 0 for each release. See the corrseponding architectural decision record for more information in the `docs/adr` directory of the source code. diff --git a/README.md b/README.md index 539a33895..699fa3f9e 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ## Background -> ⚠️ **Disclaimer:** This SDK tracks the pre-GA [GitHub Copilot SDKs](https://github.com/github/copilot-sdk) for [.NET](https://github.com/github/copilot-sdk/tree/main/dotnet) and [nodejs](https://github.com/github/copilot-sdk/tree/main/nodejs). This SDK may change in breaking ways. Use at your own risk. +> ℹ️ **Public Preview:** This SDK tracks the [GitHub Copilot SDKs](https://github.com/github/copilot-sdk) for [.NET](https://github.com/github/copilot-sdk/tree/main/dotnet) and [nodejs](https://github.com/github/copilot-sdk/tree/main/nodejs). While in public preview, minor breaking changes may still occur between releases. Java SDK for programmatic control of GitHub Copilot CLI, enabling you to build AI-powered applications and agentic workflows. diff --git a/instructions/copilot-sdk-java.instructions.md b/instructions/copilot-sdk-java.instructions.md index bf18a3c5a..7881322fd 100644 --- a/instructions/copilot-sdk-java.instructions.md +++ b/instructions/copilot-sdk-java.instructions.md @@ -6,7 +6,7 @@ name: 'GitHub Copilot SDK Java Instructions' ## Core Principles -- The SDK is in technical preview and may have breaking changes +- The SDK is in public preview and may have breaking changes - Requires Java 17 or later - Requires GitHub Copilot CLI installed and in PATH - Uses `CompletableFuture` for all async operations diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md index b599484d9..b2a85c567 100644 --- a/src/site/markdown/index.md +++ b/src/site/markdown/index.md @@ -1,6 +1,6 @@ # GitHub Copilot SDK for Java -> ⚠️ **Disclaimer:** This is the official Java SDK for GitHub Copilot. This repository treats the official .NET and nodejs SDKs for GitHub Copilot as reference implementations. These SDKS are all officially supported as GitHub open source projects. The Java implementation follows the backward compatibility guarantees offered by the reference implementations. As such this implementation may introduce breaking changes, according to the policy declared by the reference implementations. Use at your own risk. +> ℹ️ **Public Preview:** This is the official Java SDK for GitHub Copilot. This repository treats the official .NET and nodejs SDKs for GitHub Copilot as reference implementations. These SDKs are all officially supported as GitHub open source projects. The Java implementation follows the backward compatibility guarantees offered by the reference implementations. While in public preview, minor breaking changes may still occur between releases. Welcome to the documentation for the **GitHub Copilot SDK for Java** — a Java SDK for programmatic control of GitHub Copilot CLI, enabling you to build AI-powered applications and agentic workflows. From 89be8e74452f4ee6e7fcb66b96196c0efdcca54e Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Tue, 7 Apr 2026 10:32:11 -0400 Subject: [PATCH 60/80] Fix stale snapshot version in README and automate updates Update the snapshot version in README.md from 0.2.1-java.0-SNAPSHOT to 0.2.3-java.1-SNAPSHOT to match the current pom.xml. Add a sed command to the publish-maven workflow to update the snapshot version during releases, preventing it from going stale again. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/publish-maven.yml | 4 ++++ README.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-maven.yml b/.github/workflows/publish-maven.yml index f2960a756..e258a54aa 100644 --- a/.github/workflows/publish-maven.yml +++ b/.github/workflows/publish-maven.yml @@ -121,6 +121,10 @@ jobs: sed -i "s|[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\(-java\.[0-9][0-9]*\)\{0,1\}|${VERSION}|g" README.md sed -i "s|copilot-sdk-java:[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\(-java\.[0-9][0-9]*\)\{0,1\}|copilot-sdk-java:${VERSION}|g" README.md + # Update snapshot version in README.md + DEV_VERSION="${{ steps.versions.outputs.dev_version }}" + sed -i "s|[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\(-java\.[0-9][0-9]*\)\{0,1\}-SNAPSHOT|${DEV_VERSION}|g" README.md + # Update version in jbang-example.java sed -i "s|copilot-sdk-java:[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\(-java\.[0-9][0-9]*\)\{0,1\}|copilot-sdk-java:${VERSION}|g" jbang-example.java diff --git a/README.md b/README.md index 539a33895..af621d9bb 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Snapshot builds of the next development version are published to Maven Central S com.github copilot-sdk-java - 0.2.1-java.0-SNAPSHOT + 0.2.3-java.1-SNAPSHOT ``` From ef08ee6e07c022b4fdb83ff55f9294d6a0dc4cf4 Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Tue, 7 Apr 2026 10:35:55 -0400 Subject: [PATCH 61/80] Update README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 699fa3f9e..0009483f2 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ## Background -> ℹ️ **Public Preview:** This SDK tracks the [GitHub Copilot SDKs](https://github.com/github/copilot-sdk) for [.NET](https://github.com/github/copilot-sdk/tree/main/dotnet) and [nodejs](https://github.com/github/copilot-sdk/tree/main/nodejs). While in public preview, minor breaking changes may still occur between releases. +> ℹ️ **Public Preview:** This SDK tracks the [GitHub Copilot SDKs](https://github.com/github/copilot-sdk) for [.NET](https://github.com/github/copilot-sdk/tree/main/dotnet) and [Node.js](https://github.com/github/copilot-sdk/tree/main/nodejs). While in public preview, minor breaking changes may still occur between releases. Java SDK for programmatic control of GitHub Copilot CLI, enabling you to build AI-powered applications and agentic workflows. From 8069433e8bb07bb209793671196abd7a812e039b Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Tue, 7 Apr 2026 10:36:09 -0400 Subject: [PATCH 62/80] Update .github/templates/index.html Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/templates/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/templates/index.html b/.github/templates/index.html index 85b96106f..d273ad074 100644 --- a/.github/templates/index.html +++ b/.github/templates/index.html @@ -66,7 +66,7 @@

Available Versions

- ℹ️ Public Preview: This is the official Java SDK for GitHub Copilot. This repository treats the official .NET and nodejs SDKs for GitHub Copilot as reference implementations. These SDKs are all officially supported as GitHub open source projects. The Java implementation follows the backward compatibility guarantees offered by the reference implementations. While in public preview, minor breaking changes may still occur between releases. + ℹ️ Public Preview: This is the official Java SDK for GitHub Copilot. This repository treats the official .NET and Node.js SDKs for GitHub Copilot as reference implementations. These SDKs are all officially supported as GitHub open source projects. The Java implementation follows the backward compatibility guarantees offered by the reference implementations. While in public preview, minor breaking changes may still occur between releases.
From f0a82b906f55e2122c20411e457f55618a7f331a Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Tue, 7 Apr 2026 10:36:17 -0400 Subject: [PATCH 63/80] Update .github/workflows/notes.template Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/notes.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/notes.template b/.github/workflows/notes.template index 0199452eb..9c148cdf1 100644 --- a/.github/workflows/notes.template +++ b/.github/workflows/notes.template @@ -1,6 +1,6 @@ # Installation -ℹ️ **Public Preview:** This is the official Java SDK for GitHub Copilot. This repository treats the official .NET and nodejs SDKs for GitHub Copilot as reference implementations. These SDKs are all officially supported as GitHub open source projects. The Java implementation follows the backward compatibility guarantees offered by the reference implementations. While in public preview, minor breaking changes may still occur between releases. +ℹ️ **Public Preview:** This is the official Java SDK for GitHub Copilot. This repository treats the official .NET and Node.js SDKs for GitHub Copilot as reference implementations. These SDKs are all officially supported as GitHub open source projects. The Java implementation follows the backward compatibility guarantees offered by the reference implementations. While in public preview, minor breaking changes may still occur between releases. ⚠️ **Artifact versioning plan:** Releases of this implementation track releases of the reference implementation. For each release of the reference implementation, there may follow a corresponding relase of this implementation with the same number as the reference implementation. Release identifiers of the reference implementation are in the form `vMaj.Min.Micro`. For example v0.1.32. The corresponding maven version for the release will be `Maj.Min.Micro-java.N`, where `Maj`, `Min` and `Micro` are the corresponding numbers for the reference impementation release, and `N` is a monotonically increasing sequence number starting with 0 for each release. See the corrseponding architectural decision record for more information in the `docs/adr` directory of the source code. From 2dc74128c3d2179f02d7478a9adaf40ee1ee4cfd Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Tue, 7 Apr 2026 10:36:25 -0400 Subject: [PATCH 64/80] Update src/site/markdown/index.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/site/markdown/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md index b2a85c567..60b96ce9d 100644 --- a/src/site/markdown/index.md +++ b/src/site/markdown/index.md @@ -1,6 +1,6 @@ # GitHub Copilot SDK for Java -> ℹ️ **Public Preview:** This is the official Java SDK for GitHub Copilot. This repository treats the official .NET and nodejs SDKs for GitHub Copilot as reference implementations. These SDKs are all officially supported as GitHub open source projects. The Java implementation follows the backward compatibility guarantees offered by the reference implementations. While in public preview, minor breaking changes may still occur between releases. +> ℹ️ **Public Preview:** This is the official Java SDK for GitHub Copilot. This repository treats the official .NET and Node.js SDKs for GitHub Copilot as reference implementations. These SDKs are all officially supported as GitHub open source projects. The Java implementation follows the backward compatibility guarantees offered by the reference implementations. While in public preview, minor breaking changes may still occur between releases. Welcome to the documentation for the **GitHub Copilot SDK for Java** — a Java SDK for programmatic control of GitHub Copilot CLI, enabling you to build AI-powered applications and agentic workflows. From 86593d0e501621bb928151b940769b1449ee0f46 Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Tue, 7 Apr 2026 10:49:40 -0400 Subject: [PATCH 65/80] Fix jbang-example.java to use actual version instead of Maven placeholder Replace ${project.version} with a real version number (0.2.2-java.1) in jbang-example.java since this file is not Maven-filtered. Also add a fallback sed pattern in the release workflow to handle the placeholder during the transition. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/publish-maven.yml | 1 + jbang-example.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-maven.yml b/.github/workflows/publish-maven.yml index f2960a756..154ab908a 100644 --- a/.github/workflows/publish-maven.yml +++ b/.github/workflows/publish-maven.yml @@ -123,6 +123,7 @@ jobs: # Update version in jbang-example.java sed -i "s|copilot-sdk-java:[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\(-java\.[0-9][0-9]*\)\{0,1\}|copilot-sdk-java:${VERSION}|g" jbang-example.java + sed -i "s|copilot-sdk-java:\${project\.version}|copilot-sdk-java:${VERSION}|g" jbang-example.java # Update version in cookbook files (hardcoded for direct GitHub browsing and JBang usage) find src/site/markdown/cookbook -name "*.md" -type f -exec \ diff --git a/jbang-example.java b/jbang-example.java index 3d02653c1..dd1f80762 100644 --- a/jbang-example.java +++ b/jbang-example.java @@ -1,5 +1,5 @@ ! -//DEPS com.github:copilot-sdk-java:${project.version} +//DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.events.SessionUsageInfoEvent; From 0d1b0dc0c1175821df9d9fad827ae8ce9d250e07 Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Tue, 7 Apr 2026 11:04:06 -0400 Subject: [PATCH 66/80] Update .github/workflows/publish-maven.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/publish-maven.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-maven.yml b/.github/workflows/publish-maven.yml index 154ab908a..c0df3ed0d 100644 --- a/.github/workflows/publish-maven.yml +++ b/.github/workflows/publish-maven.yml @@ -123,7 +123,7 @@ jobs: # Update version in jbang-example.java sed -i "s|copilot-sdk-java:[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\(-java\.[0-9][0-9]*\)\{0,1\}|copilot-sdk-java:${VERSION}|g" jbang-example.java - sed -i "s|copilot-sdk-java:\${project\.version}|copilot-sdk-java:${VERSION}|g" jbang-example.java + sed -i 's|copilot-sdk-java:${project\.version}|copilot-sdk-java:'"${VERSION}"'|g' jbang-example.java # Update version in cookbook files (hardcoded for direct GitHub browsing and JBang usage) find src/site/markdown/cookbook -name "*.md" -type f -exec \ From 62ff965cca742ca9384560137958095d70a68d49 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Apr 2026 15:01:32 +0000 Subject: [PATCH 67/80] Initial plan From 20acdbfc0a7e43a8b5bdf06cd83cac5f2e50e236 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Apr 2026 15:08:23 +0000 Subject: [PATCH 68/80] Fix cross-platform process creation in tests: use cmd /c more on Windows Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/a5638a0d-f412-4810-b724-45bc5f10438d Co-authored-by: edburns <75821+edburns@users.noreply.github.com> --- .../com/github/copilot/sdk/CliServerManagerTest.java | 7 ++++++- .../com/github/copilot/sdk/JsonRpcClientTest.java | 11 ++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/github/copilot/sdk/CliServerManagerTest.java b/src/test/java/com/github/copilot/sdk/CliServerManagerTest.java index 32257b0a5..e59d03ae8 100644 --- a/src/test/java/com/github/copilot/sdk/CliServerManagerTest.java +++ b/src/test/java/com/github/copilot/sdk/CliServerManagerTest.java @@ -70,13 +70,18 @@ void connectToServerTcpMode() throws Exception { } } + private static Process startBlockingProcess() throws IOException { + boolean isWindows = System.getProperty("os.name").toLowerCase().contains("windows"); + return (isWindows ? new ProcessBuilder("cmd", "/c", "more") : new ProcessBuilder("cat")).start(); + } + @Test void connectToServerStdioMode() throws Exception { var options = new CopilotClientOptions(); var manager = new CliServerManager(options); // Create a dummy process for stdio mode - Process process = new ProcessBuilder("cat").start(); + Process process = startBlockingProcess(); try { JsonRpcClient client = manager.connectToServer(process, null, null); assertNotNull(client); diff --git a/src/test/java/com/github/copilot/sdk/JsonRpcClientTest.java b/src/test/java/com/github/copilot/sdk/JsonRpcClientTest.java index 8b5c1858c..4fb43f4b6 100644 --- a/src/test/java/com/github/copilot/sdk/JsonRpcClientTest.java +++ b/src/test/java/com/github/copilot/sdk/JsonRpcClientTest.java @@ -133,9 +133,14 @@ void testIsConnectedWithSocketClosed() throws Exception { pair.serverSocket.close(); } + private static Process startBlockingProcess() throws IOException { + boolean isWindows = System.getProperty("os.name").toLowerCase().contains("windows"); + return (isWindows ? new ProcessBuilder("cmd", "/c", "more") : new ProcessBuilder("cat")).start(); + } + @Test void testIsConnectedWithProcess() throws Exception { - Process proc = new ProcessBuilder("cat").start(); + Process proc = startBlockingProcess(); try (var client = JsonRpcClient.fromProcess(proc)) { assertTrue(client.isConnected()); } @@ -143,7 +148,7 @@ void testIsConnectedWithProcess() throws Exception { @Test void testIsConnectedWithProcessDead() throws Exception { - Process proc = new ProcessBuilder("cat").start(); + Process proc = startBlockingProcess(); var client = JsonRpcClient.fromProcess(proc); proc.destroy(); proc.waitFor(5, TimeUnit.SECONDS); @@ -155,7 +160,7 @@ void testIsConnectedWithProcessDead() throws Exception { @Test void testGetProcessReturnsProcess() throws Exception { - Process proc = new ProcessBuilder("cat").start(); + Process proc = startBlockingProcess(); try (var client = JsonRpcClient.fromProcess(proc)) { assertSame(proc, client.getProcess()); } From fc71b95636ac94b4816b6399233af799d657c234 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Sat, 11 Apr 2026 10:40:47 -0400 Subject: [PATCH 69/80] Fix Windows test compatibility for ProcessBuilder usage On Windows, Java's ProcessBuilder cannot directly run shell wrappers like `npx` (installed as npx.cmd) or Unix commands like `cat`. Tests that used these commands failed with "Cannot run program" errors. Additionally, Unix-style paths like "/nonexistent/copilot" are not absolute on Windows, causing assertThrows(IOException) tests to pass unexpectedly when CliServerManager wrapped them with "cmd /c". Changes: - CapiProxy: use "cmd /c npx" on Windows to launch the test harness - CliServerManagerTest: replace "cat" with cross-platform dummy process; use a platform-appropriate nonexistent absolute path so IOException is thrown on all platforms - JsonRpcClientTest: replace "cat" with cross-platform dummy process All changes use runtime os.name detection and preserve existing behavior on Linux and macOS. Full test suite passes on all platforms (556 tests, 0 failures, 0 errors). --- .../com/github/copilot/sdk/CapiProxy.java | 6 ++++- .../copilot/sdk/CliServerManagerTest.java | 26 ++++++++++++------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/test/java/com/github/copilot/sdk/CapiProxy.java b/src/test/java/com/github/copilot/sdk/CapiProxy.java index 1a7df2d6c..bcd064d94 100644 --- a/src/test/java/com/github/copilot/sdk/CapiProxy.java +++ b/src/test/java/com/github/copilot/sdk/CapiProxy.java @@ -89,7 +89,11 @@ public String start() throws IOException, InterruptedException { } // Start the harness server using npx tsx - var pb = new ProcessBuilder("npx", "tsx", "server.ts"); + // On Windows, npx is installed as npx.cmd which requires cmd /c to launch + boolean isWindows = System.getProperty("os.name").toLowerCase().contains("win"); + var pb = isWindows + ? new ProcessBuilder("cmd", "/c", "npx", "tsx", "server.ts") + : new ProcessBuilder("npx", "tsx", "server.ts"); pb.directory(harnessDir.toFile()); pb.redirectErrorStream(false); diff --git a/src/test/java/com/github/copilot/sdk/CliServerManagerTest.java b/src/test/java/com/github/copilot/sdk/CliServerManagerTest.java index e59d03ae8..e556839cc 100644 --- a/src/test/java/com/github/copilot/sdk/CliServerManagerTest.java +++ b/src/test/java/com/github/copilot/sdk/CliServerManagerTest.java @@ -131,6 +131,14 @@ void processInfoWithNullPort() { // resolveCliCommand is private, so we test indirectly through startCliServer // with specific cliPath values. + // On Windows, "/nonexistent/copilot" is not an absolute path (no drive letter), + // so resolveCliCommand wraps it with "cmd /c" and ProcessBuilder.start() + // succeeds + // (launching cmd.exe). Use a Windows-absolute path to ensure IOException. + private static final String NONEXISTENT_CLI = System.getProperty("os.name").toLowerCase().contains("win") + ? "C:\\nonexistent\\copilot" + : "/nonexistent/copilot"; + @Test void startCliServerWithJsFile() throws Exception { // Using a .js file path causes resolveCliCommand to prepend "node" @@ -152,8 +160,8 @@ void startCliServerWithJsFile() throws Exception { @Test void startCliServerWithCliArgs() throws Exception { // Test that cliArgs are included in the command - var options = new CopilotClientOptions().setCliPath("/nonexistent/copilot") - .setCliArgs(new String[]{"--extra-flag"}).setUseStdio(true); + var options = new CopilotClientOptions().setCliPath(NONEXISTENT_CLI).setCliArgs(new String[]{"--extra-flag"}) + .setUseStdio(true); var manager = new CliServerManager(options); var ex = assertThrows(IOException.class, () -> manager.startCliServer()); @@ -163,7 +171,7 @@ void startCliServerWithCliArgs() throws Exception { @Test void startCliServerWithExplicitPort() throws Exception { // Test the explicit port branch (useStdio=false, port > 0) - var options = new CopilotClientOptions().setCliPath("/nonexistent/copilot").setUseStdio(false).setPort(9999); + var options = new CopilotClientOptions().setCliPath(NONEXISTENT_CLI).setUseStdio(false).setPort(9999); var manager = new CliServerManager(options); var ex = assertThrows(IOException.class, () -> manager.startCliServer()); @@ -173,7 +181,7 @@ void startCliServerWithExplicitPort() throws Exception { @Test void startCliServerWithGitHubToken() throws Exception { // Test the github token branch - var options = new CopilotClientOptions().setCliPath("/nonexistent/copilot").setGitHubToken("ghp_test123") + var options = new CopilotClientOptions().setCliPath(NONEXISTENT_CLI).setGitHubToken("ghp_test123") .setUseStdio(true); var manager = new CliServerManager(options); @@ -184,7 +192,7 @@ void startCliServerWithGitHubToken() throws Exception { @Test void startCliServerWithUseLoggedInUserExplicit() throws Exception { // Test the explicit useLoggedInUser=false branch (adds --no-auto-login) - var options = new CopilotClientOptions().setCliPath("/nonexistent/copilot").setUseLoggedInUser(false) + var options = new CopilotClientOptions().setCliPath(NONEXISTENT_CLI).setUseLoggedInUser(false) .setUseStdio(true); var manager = new CliServerManager(options); @@ -195,7 +203,7 @@ void startCliServerWithUseLoggedInUserExplicit() throws Exception { @Test void startCliServerWithGitHubTokenAndNoExplicitUseLoggedInUser() throws Exception { // When gitHubToken is set and useLoggedInUser is null, defaults to false - var options = new CopilotClientOptions().setCliPath("/nonexistent/copilot").setGitHubToken("ghp_test123") + var options = new CopilotClientOptions().setCliPath(NONEXISTENT_CLI).setGitHubToken("ghp_test123") .setUseStdio(true); var manager = new CliServerManager(options); @@ -225,8 +233,7 @@ void startCliServerWithTelemetryAllOptions() throws Exception { // so even with a nonexistent CLI path, the telemetry code path is exercised var telemetry = new TelemetryConfig().setOtlpEndpoint("http://localhost:4318").setFilePath("/tmp/telemetry.log") .setExporterType("otlp-http").setSourceName("test-app").setCaptureContent(true); - var options = new CopilotClientOptions().setCliPath("/nonexistent/copilot").setTelemetry(telemetry) - .setUseStdio(true); + var options = new CopilotClientOptions().setCliPath(NONEXISTENT_CLI).setTelemetry(telemetry).setUseStdio(true); var manager = new CliServerManager(options); var ex = assertThrows(IOException.class, () -> manager.startCliServer()); @@ -237,8 +244,7 @@ void startCliServerWithTelemetryAllOptions() throws Exception { void startCliServerWithTelemetryCaptureContentFalse() throws Exception { // Test the false branch of getCaptureContent() var telemetry = new TelemetryConfig().setCaptureContent(false); - var options = new CopilotClientOptions().setCliPath("/nonexistent/copilot").setTelemetry(telemetry) - .setUseStdio(true); + var options = new CopilotClientOptions().setCliPath(NONEXISTENT_CLI).setTelemetry(telemetry).setUseStdio(true); var manager = new CliServerManager(options); var ex = assertThrows(IOException.class, () -> manager.startCliServer()); From 29a3c2cd81d006491724e8f618e6e06b2f8a011e Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Tue, 24 Mar 2026 14:59:20 -0400 Subject: [PATCH 70/80] On branch edburns/dd-2853206-reference-impl-not-upstream We are tracking a reference implementation, not an upstream. In `git` an `upstream` is well defined. To avoid LLM confusion, let us use the proper term. new file: .claude/skills/agentic-merge-reference-impl/SKILL.md modified: .github/copilot-instructions.md new file: .github/prompts/agentic-merge-reference-impl.prompt.md new file: .github/prompts/coding-agent-merge-reference-impl-instructions.md new file: .github/scripts/reference-impl-sync/merge-reference-impl-diff.sh new file: .github/scripts/reference-impl-sync/merge-reference-impl-finish.sh new file: .github/scripts/reference-impl-sync/merge-reference-impl-start.sh new file: .github/skills/agentic-merge-reference-impl/SKILL.md new file: .github/workflows/weekly-reference-impl-sync.lock.yml new file: .github/workflows/weekly-reference-impl-sync.md new file: .github/workflows/weekly-reference-impl-sync.yml modified: CONTRIBUTING.md modified: README.md modified: docs/WORKFLOWS.md Signed-off-by: Ed Burns --- .../agentic-merge-reference-impl/SKILL.md | 7 + .github/copilot-instructions.md | 8 +- .../agentic-merge-reference-impl.prompt.md | 439 ++++++ ...agent-merge-reference-impl-instructions.md | 19 + .../merge-reference-impl-diff.sh | 86 ++ .../merge-reference-impl-finish.sh | 63 + .../merge-reference-impl-start.sh | 88 ++ .../agentic-merge-reference-impl/SKILL.md | 7 + .../weekly-reference-impl-sync.lock.yml | 1239 +++++++++++++++++ .../workflows/weekly-reference-impl-sync.md | 151 ++ .../workflows/weekly-reference-impl-sync.yml | 181 +++ CONTRIBUTING.md | 2 +- README.md | 10 +- docs/WORKFLOWS.md | 22 +- 14 files changed, 2301 insertions(+), 21 deletions(-) create mode 100644 .claude/skills/agentic-merge-reference-impl/SKILL.md create mode 100644 .github/prompts/agentic-merge-reference-impl.prompt.md create mode 100644 .github/prompts/coding-agent-merge-reference-impl-instructions.md create mode 100755 .github/scripts/reference-impl-sync/merge-reference-impl-diff.sh create mode 100755 .github/scripts/reference-impl-sync/merge-reference-impl-finish.sh create mode 100755 .github/scripts/reference-impl-sync/merge-reference-impl-start.sh create mode 100644 .github/skills/agentic-merge-reference-impl/SKILL.md create mode 100644 .github/workflows/weekly-reference-impl-sync.lock.yml create mode 100644 .github/workflows/weekly-reference-impl-sync.md create mode 100644 .github/workflows/weekly-reference-impl-sync.yml diff --git a/.claude/skills/agentic-merge-reference-impl/SKILL.md b/.claude/skills/agentic-merge-reference-impl/SKILL.md new file mode 100644 index 000000000..421ea147b --- /dev/null +++ b/.claude/skills/agentic-merge-reference-impl/SKILL.md @@ -0,0 +1,7 @@ +--- +name: agentic-merge-reference-impl +description: Merge reference implementation changes from the official Copilot SDK into this Java SDK. +license: MIT +--- + +Follow instructions in the [agentic-merge-reference-impl prompt](../../../.github/prompts/agentic-merge-reference-impl.prompt.md) to merge reference implementation changes from the official Copilot SDK into this Java SDK. diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 284e2b800..edd40797b 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -89,9 +89,9 @@ Tests use the official copilot-sdk test harness from `https://github.com/github/ ## Key Conventions -### Upstream Merging +### Reference Implementation Merging -This SDK tracks the official .NET implementation at `github/copilot-sdk`. The `.lastmerge` file contains the last merged upstream commit hash. Use the `agentic-merge-upstream` skill (see `.github/prompts/agentic-merge-upstream.prompt.md`) to port changes. +This SDK tracks the official .NET implementation at `github/copilot-sdk`. The `.lastmerge` file contains the last merged reference implementation commit hash. Use the `agentic-merge-reference-impl` skill (see `.github/prompts/agentic-merge-reference-impl.prompt.md`) to port changes. When porting from .NET: - Adapt to Java idioms, don't copy C# patterns directly @@ -278,7 +278,7 @@ The repository has a pre-commit hook (`.githooks/pre-commit`) that is **automati - Include tests for new functionality - Update documentation if adding/changing public APIs - Reference related issues using `#issue-number` -- For upstream merges, follow the `agentic-merge-upstream` skill workflow +- For reference implementation merges, follow the `agentic-merge-reference-impl` skill workflow ## Development Workflow @@ -301,7 +301,7 @@ The release process is automated via the `publish-maven.yml` GitHub Actions work - Updates version comparison links at the bottom of CHANGELOG.md - Injects the upstream SDK commit hash (from `.lastmerge`) as a `> **Upstream sync:**` blockquote in both the new `[Unreleased]` section and the released version section -2. **Upstream Sync Tracking**: Each release records which commit from the official `github/copilot-sdk` it is synced to: +2. **Reference Implementation Sync Tracking**: Each release records which commit from the official `github/copilot-sdk` it is synced to: - The `.lastmerge` file is read during the release workflow - The commit hash is injected into `CHANGELOG.md` under the release heading - Format: `> **Upstream sync:** [\`github/copilot-sdk@SHORT_HASH\`](link-to-commit)` diff --git a/.github/prompts/agentic-merge-reference-impl.prompt.md b/.github/prompts/agentic-merge-reference-impl.prompt.md new file mode 100644 index 000000000..fd7c3fa13 --- /dev/null +++ b/.github/prompts/agentic-merge-reference-impl.prompt.md @@ -0,0 +1,439 @@ +# Merge Reference Implementation SDK Changes + +You are an expert Java developer tasked with porting changes from the reference implementation of the Copilot SDK (primarily the .NET implementation) to this Java SDK. + +## ⚠️ IMPORTANT: Java SDK Design Takes Priority + +**The current design and architecture of the Java SDK is the priority.** When porting changes from the reference implementation: + +1. **Adapt, don't copy** - Translate reference implementation features to fit the Java SDK's existing patterns, naming conventions, and architecture +2. **Preserve Java idioms** - The Java SDK should feel natural to Java developers, not like a C# port +3. **Maintain consistency** - New code must match the existing codebase style and structure +4. **Evaluate before porting** - Not every reference implementation change needs to be ported; some may not be applicable or may conflict with Java SDK design decisions + +Before making any changes, **read and understand the existing Java SDK implementation** to ensure new code integrates seamlessly. + +## Utility Scripts + +The `.github/scripts/` directory contains helper scripts that automate the repeatable parts of this workflow. **Use these scripts instead of running the commands manually.** + +| Script | Purpose | +|---|---| +| `.github/scripts/reference-impl-sync/merge-reference-impl-start.sh` | Creates branch, updates CLI, clones reference implementation, reads `.lastmerge`, prints commit summary | +| `.github/scripts/reference-impl-sync/merge-reference-impl-diff.sh` | Detailed diff analysis grouped by area (`.NET src`, tests, snapshots, docs, etc.) | +| `.github/scripts/reference-impl-sync/merge-reference-impl-finish.sh` | Runs format + test + build, updates `.lastmerge`, commits, pushes branch | +| `.github/scripts/build/format-and-test.sh` | Standalone `spotless:apply` + `mvn clean verify` (useful during porting too) | + +All scripts write/read a `.merge-env` file (git-ignored) to share state (branch name, reference-impl dir, last-merge commit). + +## Workflow Overview + +1. Run `./.github/scripts/reference-impl-sync/merge-reference-impl-start.sh` (creates branch, clones reference implementation, shows summary) +2. Run `./.github/scripts/reference-impl-sync/merge-reference-impl-diff.sh` (analyze changes) +3. Update README with minimum CLI version requirement +4. Identify reference implementation changes to port +5. Apply changes to Java SDK (commit as you go) +6. Port/adjust tests from reference implementation changes +7. Run `./.github/scripts/build/format-and-test.sh` frequently while porting +8. Build the package +9. Update documentation (**required for every user-facing reference implementation change**) +10. Run `./.github/scripts/reference-impl-sync/merge-reference-impl-finish.sh` (final test + push) and finalize Pull Request (see note below about coding agent vs. manual workflow) +11. Perform final review before handing off + +--- + +## Step 1: Initialize Reference Implementation Sync + +Run the start script to create a branch, update the CLI, clone the reference implementation repo, and see a summary of new commits: + +```bash +./.github/scripts/reference-impl-sync/merge-reference-impl-start.sh +``` + +This writes a `.merge-env` file used by the other scripts. It outputs: +- The branch name created +- The Copilot CLI version +- The reference-impl dir path +- A short log of reference implementation commits since `.lastmerge` + +## Step 2: Analyze Upstream Changes + +Run the diff script for a detailed breakdown by area: + +```bash +./.github/scripts/reference-impl-sync/merge-reference-impl-diff.sh # stat only +./.github/scripts/reference-impl-sync/merge-reference-impl-diff.sh --full # full diffs +``` + +The diff script groups changes into: .NET source, .NET tests, test snapshots, documentation, protocol/config, Go/Node.js/Python SDKs, and other files. + +## Step 3: Update README with CLI Version + +After the start script runs, check the CLI version it printed (also saved in `.merge-env` as `CLI_VERSION`). Update the Requirements section in `README.md` and `src/site/markdown/index.md` to specify the minimum CLI version requirement. + +Commit this change before proceeding: + +```bash +git add README.md src/site/markdown/index.md +git commit -m "Update Copilot CLI minimum version requirement" +``` + +## Step 4: Identify Changes to Port + +Using the output from `merge-reference-impl-diff.sh`, focus on: +- `dotnet/src/` - Primary reference implementation +- `dotnet/test/` - Test cases to port +- `docs/` - Documentation updates +- `sdk-protocol-version.json` - Protocol version changes + +For each change in the reference implementation diff, determine: + +1. **New Features**: New methods, classes, or capabilities added to the SDK +2. **Bug Fixes**: Corrections to existing functionality +3. **API Changes**: Changes to public interfaces or method signatures +4. **Protocol Updates**: Changes to the JSON-RPC protocol or message types +5. **Test Updates**: New or modified test cases + +### Key Files to Compare + +| Upstream (.NET) | Java SDK Equivalent | +|------------------------------------|--------------------------------------------------------| +| `dotnet/src/Client.cs` | `src/main/java/com/github/copilot/sdk/CopilotClient.java` | +| `dotnet/src/Session.cs` | `src/main/java/com/github/copilot/sdk/CopilotSession.java` | +| `dotnet/src/Types.cs` | `src/main/java/com/github/copilot/sdk/types/*.java` | +| `dotnet/src/Generated/*.cs` | `src/main/java/com/github/copilot/sdk/types/*.java` | +| `dotnet/test/*.cs` | `src/test/java/com/github/copilot/sdk/*Test.java` | +| `docs/getting-started.md` | `README.md` and `src/site/markdown/*.md` | +| `docs/*.md` (new files) | `src/site/markdown/*.md` + update `src/site/site.xml` | +| `sdk-protocol-version.json` | (embedded in Java code or resource file) | + +> **⚠️ Important:** When adding new documentation pages, always update `src/site/site.xml` to include them in the navigation menu. + +## Step 5: Apply Changes to Java SDK + +When porting changes: + +### ⚠️ Priority: Preserve Java SDK Design + +Before modifying any code: + +1. **Read the existing Java implementation first** - Understand current patterns, class structure, and naming +2. **Identify the Java equivalent approach** - Don't replicate C# patterns; find the idiomatic Java way +3. **Check for existing abstractions** - The Java SDK may already have mechanisms that differ from .NET +4. **Preserve backward compatibility** - Existing API signatures should not break unless absolutely necessary +5. **When in doubt, match existing code** - Follow what's already in the Java SDK, not the upstream + +### Commit Changes Incrementally + +**Important:** Commit your changes as you work, grouping related changes together: + +```bash +# After porting a feature or fix, commit with a descriptive message +git add +git commit -m "Port from the reference implementation" + +# Example commits: +# git commit -m "Port new authentication flow from the reference implementation" +# git commit -m "Add new message types from the reference implementation protocol update" +# git commit -m "Port bug fix for session handling from the reference implementation" +``` + +This creates a clear history of changes that can be reviewed in the Pull Request. + +### General Guidelines + +- **Naming Conventions**: Convert C# PascalCase to Java camelCase for methods/variables +- **Async Patterns**: C# `async/await` → Java `CompletableFuture` or synchronous equivalents +- **Nullable Types**: C# `?` nullable → Java `@Nullable` annotations or `Optional` +- **Properties**: C# properties → Java getters/setters or records +- **Records**: C# records → Java records (Java 17+) +- **Events**: C# events → Java callbacks or listeners + +### Type Mappings + +| C# Type | Java Equivalent | +|------------------------|------------------------------| +| `string` | `String` | +| `int` | `int` / `Integer` | +| `bool` | `boolean` / `Boolean` | +| `Task` | `CompletableFuture` | +| `CancellationToken` | (custom implementation) | +| `IAsyncEnumerable` | `Stream` or `Iterator` | +| `JsonElement` | `JsonNode` (Jackson) | +| `Dictionary` | `Map` | +| `List` | `List` | + +### Code Style + +Follow the existing Java SDK patterns: +- Use Jackson for JSON serialization (`ObjectMapper`) +- Use Java records for DTOs where appropriate +- Follow the existing package structure under `com.github.copilot.sdk` +- Maintain backward compatibility when possible +- **Match the style of surrounding code** - Consistency with existing code is more important than reference implementation patterns +- **Prefer existing abstractions** - If the Java SDK already solves a problem differently than .NET, keep the Java approach + +## Step 6: Port Tests + +After porting implementation changes, **always check for new or updated tests** in the reference implementation repository: + +### Check for New Tests + +```bash +cd "$TEMP_DIR/copilot-sdk" +git diff "$LAST_MERGE_COMMIT"..origin/main --stat -- dotnet/test/ +git diff "$LAST_MERGE_COMMIT"..origin/main --stat -- test/snapshots/ +``` + +### Port Test Cases + +For each new or modified test file in `dotnet/test/`: + +1. **Create corresponding Java test class** in `src/test/java/com/github/copilot/sdk/` +2. **Follow existing test patterns** - Look at existing tests like `PermissionsTest.java` for structure +3. **Use the E2ETestContext** infrastructure for tests that need the test harness +4. **Match snapshot directory names** - Test snapshots in `test/snapshots/` must match the directory name used in `ctx.configureForTest()` + +### Test File Mapping + +| Upstream Test (.NET) | Java SDK Test | +|-----------------------------|--------------------------------------------------------| +| `dotnet/test/AskUserTests.cs` | `src/test/java/com/github/copilot/sdk/AskUserTest.java` | +| `dotnet/test/HooksTests.cs` | `src/test/java/com/github/copilot/sdk/HooksTest.java` | +| `dotnet/test/ClientTests.cs` | `src/test/java/com/github/copilot/sdk/CopilotClientTest.java` | +| `dotnet/test/*Tests.cs` | `src/test/java/com/github/copilot/sdk/*Test.java` | + +### Test Snapshot Compatibility + +New test snapshots are stored in `test/snapshots/` in the reference implementation repository. These snapshots are automatically cloned during the Maven build process. + +If tests fail with errors like `TypeError: Cannot read properties of undefined`, the test harness may not yet support the new RPC methods. In this case: + +1. **Mark tests as `@Disabled`** with a clear reason (e.g., `@Disabled("Requires test harness update with X support - see upstream PR #NNN")`) +2. **Document the dependency** in the test class Javadoc +3. **Enable tests later** once the harness is updated + +### Unit Tests vs E2E Tests + +- **Unit tests** (like auth option validation) can run without the test harness +- **E2E tests** require the test harness with matching snapshots + +Commit tests separately or together with their corresponding implementation changes. + +## Step 7: Format and Run Tests + +After applying changes, use the convenience script: + +```bash +./.github/scripts/build/format-and-test.sh # format + full verify +./.github/scripts/build/format-and-test.sh --debug # with debug logging +``` + +Or for quicker iteration during porting: + +```bash +./.github/scripts/build/format-and-test.sh --format-only # just spotless +./.github/scripts/build/format-and-test.sh --test-only # skip formatting +``` + +### If Tests Fail + +1. Read the test output carefully +2. Identify the root cause (compilation error, runtime error, assertion failure) +3. Fix the issue in the Java code +4. Re-run tests +5. Repeat until all tests pass + +### Common Issues + +- **Missing imports**: Add required import statements +- **Type mismatches**: Ensure proper type conversions +- **Null handling**: Add null checks where C# had nullable types +- **JSON serialization**: Verify Jackson annotations are correct + +## Step 8: Build the Package + +Once tests pass, build the complete package: + +```bash +mvn clean package -DskipTests +``` + +Verify: +- No compilation errors +- No warnings (if possible) +- JAR file is generated in `target/` + +## Step 9: Update Documentation + +**Documentation is critical for new features.** Every new feature ported from the reference implementation must be documented before the merge is complete. +Review and complete this documentation checklist before proceeding to Step 10. +If you determine no docs changes are needed, document that decision and rationale in the PR body under a clear heading (for example, `Documentation Impact`). + +### Documentation Checklist + +For each new feature or significant change: + +1. **README.md**: Update the main README if there are user-facing changes +2. **src/site/markdown/index.md**: Update if requirements or quick start examples change +3. **src/site/markdown/documentation.md**: Add sections for new basic usage patterns +4. **src/site/markdown/advanced.md**: Add sections for new advanced features (tools, handlers, configurations) +5. **src/site/markdown/mcp.md**: Update if MCP-related changes are made +6. **Javadoc**: Add/update Javadoc comments for all new/changed public APIs +7. **src/site/site.xml**: Update if new documentation pages were added + +### Documentation Requirements for New Features + +When adding a new feature, ensure the documentation includes: + +- **What it does**: Clear explanation of the feature's purpose +- **How to use it**: Code example showing typical usage +- **API reference**: Link to relevant Javadoc +- **Configuration options**: All available settings/properties + +### Example: Documenting a New Handler + +If a new handler (like `UserInputHandler`, `PermissionHandler`) is added, create a section in `advanced.md`: + +```markdown +## Feature Name + +Brief description of what the feature does. + +\`\`\`java +var session = client.createSession( + new SessionConfig() + .setOnFeatureRequest((request, invocation) -> { + // Handle the request + return CompletableFuture.completedFuture(result); + }) +).get(); +\`\`\` + +Explain the request/response objects and their properties. + +See [FeatureHandler](apidocs/com/github/copilot/sdk/json/FeatureHandler.html) Javadoc for more details. +``` + +### Verify Documentation Consistency + +Ensure consistency across all documentation files: + +- Requirements section should match in `README.md` and `src/site/markdown/index.md` +- Code examples should use the same patterns and be tested +- Links to Javadoc should use correct paths (`apidocs/...`) + +## Step 10: Finish, Push, and Finalize Pull Request + +Run the finish script which updates `.lastmerge`, runs a final build, and pushes the branch: + +```bash +./.github/scripts/reference-impl-sync/merge-reference-impl-finish.sh # full format + test + push +./.github/scripts/reference-impl-sync/merge-reference-impl-finish.sh --skip-tests # if tests already passed +``` + +### PR Handling: Coding Agent vs. Manual Workflow + +**If running as a Copilot coding agent** (triggered via GitHub issue assignment by the weekly sync workflow), a pull request has **already been created automatically** for you. Do NOT create a new one. Just push your commits to the current branch — the existing PR will be updated. Add the `reference-impl-sync` label to the existing PR by running this command in a terminal: + +```bash +gh pr edit --add-label "reference-impl-sync" +``` + +> **No-changes scenario (coding agent only):** If after analyzing the reference implementation diff there are no relevant changes to port to the Java SDK, push an empty commit with a message explaining why no changes were needed, so the PR reflects the analysis outcome. The repository maintainer will close the PR and issue manually. + +**If running manually** (e.g., from VS Code via the reusable prompt), create the Pull Request using `gh` CLI or the GitHub MCP tool. Then add the label: + +```bash +gh pr create --base main --title "Merge reference implementation SDK changes (YYYY-MM-DD)" --body-file /dev/stdin <<< "$PR_BODY" +gh pr edit --add-label "reference-impl-sync" +``` + +The PR body should include: +1. **Title**: `Merge reference implementation SDK changes (YYYY-MM-DD)` +2. **Body** with: + - Summary of reference implementation commits analyzed (with count and commit range) + - Table of changes ported (commit hash + description) + - List of changes intentionally not ported (with reasons) + - Verification status (test count, build status) + +### PR Body Template + +```markdown +## Reference Implementation Merge + +Ports changes from the official Copilot SDK ([github/copilot-sdk](https://github.com/github/copilot-sdk)) since last merge (``→``). + +### Reference implementation commits analyzed (N commits) + +- Brief description of each reference implementation change and whether it was ported or not + +### Changes ported + +| Commit | Description | +|---|---| +| `` | Description of change | + +### Not ported (intentionally) + +- **Feature name** — Reason why it wasn't ported + +### Verification + +- All **N tests pass** (`mvn clean test`) +- Package builds successfully (`mvn clean package -DskipTests`) +- Code formatted with Spotless +``` + +## Step 11: Final Review + +Before finishing: + +1. Run `git log --oneline main..$BRANCH_NAME` to review all commits +2. Run `git diff main..$BRANCH_NAME --stat` to see a summary of all changes +3. Ensure no unintended changes were made +4. Verify code follows project conventions +5. Confirm the branch was pushed to remote +6. Confirm the Pull Request is ready (created or updated) and provide the PR URL to the user + +--- + +## Checklist + +- [ ] New branch created from `main` +- [ ] Copilot CLI updated to latest version +- [ ] README.md updated with minimum CLI version requirement +- [ ] Upstream repository cloned +- [ ] Diff analyzed between `.lastmerge` commit and HEAD +- [ ] New features/fixes identified +- [ ] Changes ported to Java SDK following conventions +- [ ] **New/updated tests ported from the reference implementation** (check `dotnet/test/` and `test/snapshots/`) +- [ ] Tests marked `@Disabled` if harness doesn't support new features yet +- [ ] Changes committed incrementally with descriptive messages +- [ ] `mvn test` passes +- [ ] `mvn package` builds successfully +- [ ] **Documentation updated for new features:** + - [ ] `README.md` updated if user-facing changes + - [ ] `src/site/markdown/index.md` updated if requirements changed + - [ ] `src/site/markdown/documentation.md` updated for new basic usage + - [ ] `src/site/markdown/advanced.md` updated for new advanced features + - [ ] Javadoc added/updated for new public APIs +- [ ] If no documentation files were changed for user-facing reference implementation changes, PR body explicitly explains why documentation changes were not needed +- [ ] `src/site/site.xml` updated if new documentation pages were added +- [ ] `.lastmerge` file updated with new commit hash +- [ ] Branch pushed to remote +- [ ] **Pull Request finalized** (coding agent: push to existing PR; manual: create via `mcp_github_create_pull_request`) +- [ ] **`reference-impl-sync` label added** to the PR via `mcp_github_add_issue_labels` +- [ ] PR URL provided to user + +--- + +## Notes + +- The reference implementation SDK is at: `https://github.com/github/copilot-sdk.git` +- Primary reference implementation is in `dotnet/` folder +- This Java SDK targets Java 17+ +- Uses Jackson for JSON processing +- Uses JUnit 5 for testing +- **Java SDK design decisions take precedence over reference implementation patterns** +- **Adapt reference implementation changes to fit Java idioms, not the other way around** diff --git a/.github/prompts/coding-agent-merge-reference-impl-instructions.md b/.github/prompts/coding-agent-merge-reference-impl-instructions.md new file mode 100644 index 000000000..cee6ef8a7 --- /dev/null +++ b/.github/prompts/coding-agent-merge-reference-impl-instructions.md @@ -0,0 +1,19 @@ + + + +Follow the agentic-merge-reference-impl prompt at .github/prompts/agentic-merge-reference-impl.prompt.md +to port reference implementation changes to the Java SDK. + +Use the utility scripts in .github/scripts/ subfolders for initialization, diffing, formatting, and testing. +Commit changes incrementally. Update .lastmerge when done. + +IMPORTANT: A pull request has already been created automatically for you — do NOT create a new +one. Push your commits to the current branch, and the existing PR will be updated. + +Add the 'reference-impl-sync' label to the existing PR by running this command in a terminal: + + gh pr edit --add-label "reference-impl-sync" + +If after analyzing the reference implementation diff there are no relevant changes to port to the Java SDK, +push an empty commit with a message explaining why no changes were needed, so the PR reflects +the analysis outcome. The repository maintainer will close the PR and issue manually. diff --git a/.github/scripts/reference-impl-sync/merge-reference-impl-diff.sh b/.github/scripts/reference-impl-sync/merge-reference-impl-diff.sh new file mode 100755 index 000000000..8ff870103 --- /dev/null +++ b/.github/scripts/reference-impl-sync/merge-reference-impl-diff.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +# ────────────────────────────────────────────────────────────── +# merge-reference-impl-diff.sh +# +# Generates a detailed diff analysis of reference implementation changes since +# the last merge, grouped by area of interest: +# • .NET source (primary reference) +# • .NET tests +# • Test snapshots +# • Documentation +# • Protocol / config files +# +# Usage: ./.github/scripts/reference-impl-sync/merge-reference-impl-diff.sh [--full] +# --full Show actual diffs, not just stats +# +# Requires: .merge-env written by merge-reference-impl-start.sh +# ────────────────────────────────────────────────────────────── +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "$0")/../../.." && pwd)" +ENV_FILE="$ROOT_DIR/.merge-env" + +if [[ ! -f "$ENV_FILE" ]]; then + echo "❌ $ENV_FILE not found. Run ./.github/scripts/reference-impl-sync/merge-reference-impl-start.sh first." + exit 1 +fi + +# shellcheck source=/dev/null +source "$ENV_FILE" + +SHOW_FULL=false +if [[ "${1:-}" == "--full" ]]; then + SHOW_FULL=true +fi + +cd "$REFERENCE_IMPL_DIR" +git fetch origin main 2>/dev/null + +RANGE="$LAST_MERGE_COMMIT..origin/main" + +echo "════════════════════════════════════════════════════════════" +echo " Reference implementation diff analysis: $RANGE" +echo "════════════════════════════════════════════════════════════" + +# ── Commit log ──────────────────────────────────────────────── +echo "" +echo "── Commit log ──" +git log --oneline --no-decorate "$RANGE" +echo "" + +# Helper to print a section +section() { + local title="$1"; shift + local paths=("$@") + + echo "── $title ──" + local stat + stat=$(git diff "$RANGE" --stat -- "${paths[@]}" 2>/dev/null || true) + if [[ -z "$stat" ]]; then + echo " (no changes)" + else + echo "$stat" + if $SHOW_FULL; then + echo "" + git diff "$RANGE" -- "${paths[@]}" 2>/dev/null || true + fi + fi + echo "" +} + +# ── Sections ────────────────────────────────────────────────── +section ".NET source (dotnet/src)" "dotnet/src/" +section ".NET tests (dotnet/test)" "dotnet/test/" +section "Test snapshots" "test/snapshots/" +section "Documentation (docs/)" "docs/" +section "Protocol & config" "sdk-protocol-version.json" "package.json" "justfile" +section "Go SDK" "go/" +section "Node.js SDK" "nodejs/" +section "Python SDK" "python/" +section "Other files" "README.md" "CONTRIBUTING.md" "SECURITY.md" "SUPPORT.md" + +echo "════════════════════════════════════════════════════════════" +echo " To see full diffs: $0 --full" +echo " To see a specific path:" +echo " cd $REFERENCE_IMPL_DIR && git diff $RANGE -- " +echo "════════════════════════════════════════════════════════════" diff --git a/.github/scripts/reference-impl-sync/merge-reference-impl-finish.sh b/.github/scripts/reference-impl-sync/merge-reference-impl-finish.sh new file mode 100755 index 000000000..480d43bc0 --- /dev/null +++ b/.github/scripts/reference-impl-sync/merge-reference-impl-finish.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +# ────────────────────────────────────────────────────────────── +# merge-reference-impl-finish.sh +# +# Finalises a reference implementation merge: +# 1. Runs format + test + build (via format-and-test.sh) +# 2. Updates .lastmerge to reference implementation HEAD +# 3. Commits the .lastmerge update +# 4. Pushes the branch to origin +# +# Usage: ./.github/scripts/reference-impl-sync/merge-reference-impl-finish.sh +# ./.github/scripts/reference-impl-sync/merge-reference-impl-finish.sh --skip-tests +# +# Requires: .merge-env written by merge-reference-impl-start.sh +# ────────────────────────────────────────────────────────────── +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "$0")/../../.." && pwd)" +ENV_FILE="$ROOT_DIR/.merge-env" + +if [[ ! -f "$ENV_FILE" ]]; then + echo "❌ $ENV_FILE not found. Run ./.github/scripts/reference-impl-sync/merge-reference-impl-start.sh first." + exit 1 +fi + +# shellcheck source=/dev/null +source "$ENV_FILE" + +SKIP_TESTS=false +if [[ "${1:-}" == "--skip-tests" ]]; then + SKIP_TESTS=true +fi + +cd "$ROOT_DIR" + +# ── 1. Format, test, build ─────────────────────────────────── +if $SKIP_TESTS; then + echo "▸ Formatting only (tests skipped)…" + mvn spotless:apply + mvn clean package -DskipTests +else + echo "▸ Running format + test + build…" + "$ROOT_DIR/.github/scripts/build/format-and-test.sh" +fi + +# ── 2. Update .lastmerge ───────────────────────────────────── +echo "▸ Updating .lastmerge…" +NEW_COMMIT=$(cd "$REFERENCE_IMPL_DIR" && git rev-parse origin/main) +echo "$NEW_COMMIT" > "$ROOT_DIR/.lastmerge" + +git add .lastmerge +git commit -m "Update .lastmerge to $NEW_COMMIT" + +# ── 3. Push branch ─────────────────────────────────────────── +echo "▸ Pushing branch $BRANCH_NAME to origin…" +git push -u origin "$BRANCH_NAME" + +echo "" +echo "✅ Branch pushed. Next step:" +echo " Create a Pull Request (base: main, head: $BRANCH_NAME)" +echo "" +echo " Suggested title: Merge reference implementation SDK changes ($(date +%Y-%m-%d))" +echo " Don't forget to add the 'reference-impl-sync' label." diff --git a/.github/scripts/reference-impl-sync/merge-reference-impl-start.sh b/.github/scripts/reference-impl-sync/merge-reference-impl-start.sh new file mode 100755 index 000000000..76408e4ec --- /dev/null +++ b/.github/scripts/reference-impl-sync/merge-reference-impl-start.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env bash +# ────────────────────────────────────────────────────────────── +# merge-reference-impl-start.sh +# +# Prepares the workspace for a reference implementation merge: +# 1. Creates a dated branch from main +# 2. Updates Copilot CLI and records the new version +# 3. Clones the reference implementation copilot-sdk repo into a temp dir +# 4. Reads .lastmerge and prints a short summary of new commits +# +# Usage: ./.github/scripts/reference-impl-sync/merge-reference-impl-start.sh +# Output: Exports REFERENCE_IMPL_DIR and LAST_MERGE_COMMIT to a +# .merge-env file so other scripts can source it. +# ────────────────────────────────────────────────────────────── +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "$0")/../../.." && pwd)" +cd "$ROOT_DIR" + +REFERENCE_IMPL_REPO="https://github.com/github/copilot-sdk.git" +ENV_FILE="$ROOT_DIR/.merge-env" + +# ── 1. Create branch (or reuse existing) ───────────────────── +CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) + +if [[ "$CURRENT_BRANCH" != "main" ]]; then + # Already on a non-main branch (e.g., coding agent's auto-created PR branch). + # Stay on this branch — do not create a new one. + BRANCH_NAME="$CURRENT_BRANCH" + echo "▸ Already on branch '$BRANCH_NAME' — reusing it (coding agent mode)." + git pull origin main --no-edit 2>/dev/null || echo " (pull from main skipped or fast-forward not possible)" +else + echo "▸ Ensuring main is up to date…" + git pull origin main + + BRANCH_NAME="merge-reference-impl-$(date +%Y%m%d)" + echo "▸ Creating branch: $BRANCH_NAME" + git checkout -b "$BRANCH_NAME" +fi + +# ── 2. Update Copilot CLI ──────────────────────────────────── +echo "▸ Updating Copilot CLI…" +if command -v copilot &>/dev/null; then + copilot update || echo " (copilot update returned non-zero – check manually)" + CLI_VERSION=$(copilot --version | head -n 1 | awk '{print $NF}') + echo " Copilot CLI version: $CLI_VERSION" +else + echo " ⚠ 'copilot' command not found – skipping CLI update." + CLI_VERSION="UNKNOWN" +fi + +# ── 3. Clone reference implementation ──────────────────────────────────────── +TEMP_DIR=$(mktemp -d) +REFERENCE_IMPL_DIR="$TEMP_DIR/copilot-sdk" +echo "▸ Cloning reference implementation into $REFERENCE_IMPL_DIR …" +git clone --depth=200 "$REFERENCE_IMPL_REPO" "$REFERENCE_IMPL_DIR" + +# ── 4. Read last merge commit ──────────────────────────────── +if [[ ! -f "$ROOT_DIR/.lastmerge" ]]; then + echo "❌ .lastmerge file not found in repo root." + exit 1 +fi +LAST_MERGE_COMMIT=$(tr -d '[:space:]' < "$ROOT_DIR/.lastmerge") +echo "▸ Last merged reference implementation commit: $LAST_MERGE_COMMIT" + +# Quick summary +echo "" +echo "── Reference implementation commits since last merge ──" +(cd "$REFERENCE_IMPL_DIR" && git fetch origin main && \ + git log --oneline "$LAST_MERGE_COMMIT"..origin/main) || \ + echo " (could not generate log – the commit may have been rebased)" +echo "" + +# ── 5. Write env file for other scripts ────────────────────── +cat > "$ENV_FILE" < + GH_AW_PROMPT_EOF + cat "/opt/gh-aw/prompts/xpia.md" + cat "/opt/gh-aw/prompts/temp_folder_prompt.md" + cat "/opt/gh-aw/prompts/markdown.md" + cat "/opt/gh-aw/prompts/safe_outputs_prompt.md" + cat << 'GH_AW_PROMPT_EOF' + + Tools: add_comment, create_issue, close_issue, assign_to_agent, missing_tool, missing_data, noop + + + The following GitHub context information is available for this workflow: + {{#if __GH_AW_GITHUB_ACTOR__ }} + - **actor**: __GH_AW_GITHUB_ACTOR__ + {{/if}} + {{#if __GH_AW_GITHUB_REPOSITORY__ }} + - **repository**: __GH_AW_GITHUB_REPOSITORY__ + {{/if}} + {{#if __GH_AW_GITHUB_WORKSPACE__ }} + - **workspace**: __GH_AW_GITHUB_WORKSPACE__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }} + - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }} + - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }} + - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }} + - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__ + {{/if}} + {{#if __GH_AW_GITHUB_RUN_ID__ }} + - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__ + {{/if}} + + + GH_AW_PROMPT_EOF + cat << 'GH_AW_PROMPT_EOF' + + GH_AW_PROMPT_EOF + cat << 'GH_AW_PROMPT_EOF' + {{#runtime-import .github/workflows/weekly-reference-impl-sync.md}} + GH_AW_PROMPT_EOF + } > "$GH_AW_PROMPT" + - name: Interpolate variables and render templates + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + with: + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('/opt/gh-aw/actions/interpolate_prompt.cjs'); + await main(); + - name: Substitute placeholders + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_GITHUB_ACTOR: ${{ github.actor }} + GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} + GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} + GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} + GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} + GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} + GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} + GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} + with: + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + + const substitutePlaceholders = require('/opt/gh-aw/actions/substitute_placeholders.cjs'); + + // Call the substitution function + return await substitutePlaceholders({ + file: process.env.GH_AW_PROMPT, + substitutions: { + GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR, + GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID, + GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER, + GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER, + GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER, + GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY, + GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID, + GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE + } + }); + - name: Validate prompt placeholders + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + run: bash /opt/gh-aw/actions/validate_prompt_placeholders.sh + - name: Print prompt + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + run: bash /opt/gh-aw/actions/print_prompt_summary.sh + - name: Upload activation artifact + if: success() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: activation + path: | + /tmp/gh-aw/aw_info.json + /tmp/gh-aw/aw-prompts/prompt.txt + retention-days: 1 + + agent: + needs: activation + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + issues: read + concurrency: + group: "gh-aw-copilot-${{ github.workflow }}" + env: + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + GH_AW_ASSETS_ALLOWED_EXTS: "" + GH_AW_ASSETS_BRANCH: "" + GH_AW_ASSETS_MAX_SIZE_KB: 0 + GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs + GH_AW_SAFE_OUTPUTS: /opt/gh-aw/safeoutputs/outputs.jsonl + GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json + GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json + GH_AW_WORKFLOW_ID_SANITIZED: weeklyreferenceimplsync + outputs: + checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} + detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }} + detection_success: ${{ steps.detection_conclusion.outputs.success }} + has_patch: ${{ steps.collect_output.outputs.has_patch }} + model: ${{ needs.activation.outputs.model }} + output: ${{ steps.collect_output.outputs.output }} + output_types: ${{ steps.collect_output.outputs.output_types }} + steps: + - name: Setup Scripts + uses: github/gh-aw/actions/setup@33cd6c7f1fee588654ef19def2e6a4174be66197 # v0.51.6 + with: + destination: /opt/gh-aw/actions + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - name: Create gh-aw temp directory + run: bash /opt/gh-aw/actions/create_gh_aw_tmp_dir.sh + - name: Configure Git credentials + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + git config --global am.keepcr true + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" + - name: Checkout PR branch + id: checkout-pr + if: | + (github.event.pull_request) || (github.event.issue.pull_request) + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + with: + github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('/opt/gh-aw/actions/checkout_pr_branch.cjs'); + await main(); + - name: Install GitHub Copilot CLI + run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.420 + - name: Install awf binary + run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.23.0 + - name: Determine automatic lockdown mode for GitHub MCP Server + id: determine-automatic-lockdown + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} + GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} + with: + script: | + const determineAutomaticLockdown = require('/opt/gh-aw/actions/determine_automatic_lockdown.cjs'); + await determineAutomaticLockdown(github, context, core); + - name: Download container images + run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.6 ghcr.io/github/github-mcp-server:v0.31.0 node:lts-alpine + - name: Write Safe Outputs Config + run: | + mkdir -p /opt/gh-aw/safeoutputs + mkdir -p /tmp/gh-aw/safeoutputs + mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs + cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF' + {"add_comment":{"max":10,"target":"*"},"assign_to_agent":{"default_agent":"copilot","max":1,"target":"*"},"close_issue":{"max":10,"required_labels":["reference-impl-sync"],"target":"*"},"create_issue":{"expires":144,"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1}} + GH_AW_SAFE_OUTPUTS_CONFIG_EOF + cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF' + [ + { + "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 1 issue(s) can be created. Title will be prefixed with \"[reference-impl-sync] \". Labels [reference-impl-sync] will be automatically added. Assignees [copilot] will be automatically assigned.", + "inputSchema": { + "additionalProperties": false, + "properties": { + "body": { + "description": "Detailed issue description in Markdown. Do NOT repeat the title as a heading since it already appears as the issue's h1. Include context, reproduction steps, or acceptance criteria as appropriate.", + "type": "string" + }, + "labels": { + "description": "Labels to categorize the issue (e.g., 'bug', 'enhancement'). Labels must exist in the repository.", + "items": { + "type": "string" + }, + "type": "array" + }, + "parent": { + "description": "Parent issue number for creating sub-issues. This is the numeric ID from the GitHub URL (e.g., 42 in github.com/owner/repo/issues/42). Can also be a temporary_id (e.g., 'aw_abc123', 'aw_Test123') from a previously created issue in the same workflow run.", + "type": [ + "number", + "string" + ] + }, + "temporary_id": { + "description": "Unique temporary identifier for referencing this issue before it's created. Format: 'aw_' followed by 3 to 8 alphanumeric characters (e.g., 'aw_abc1', 'aw_Test123'). Use '#aw_ID' in body text to reference other issues by their temporary_id; these are replaced with actual issue numbers after creation.", + "pattern": "^aw_[A-Za-z0-9]{3,8}$", + "type": "string" + }, + "title": { + "description": "Concise issue title summarizing the bug, feature, or task. The title appears as the main heading, so keep it brief and descriptive.", + "type": "string" + } + }, + "required": [ + "title", + "body" + ], + "type": "object" + }, + "name": "create_issue" + }, + { + "description": "Close a GitHub issue with a closing comment. You can and should always add a comment when closing an issue to explain the action or provide context. This tool is ONLY for closing issues - use update_issue if you need to change the title, body, labels, or other metadata without closing. Use close_issue when work is complete, the issue is no longer relevant, or it's a duplicate. The closing comment should explain the resolution or reason for closing. If the issue is already closed, a comment will still be posted. CONSTRAINTS: Maximum 10 issue(s) can be closed. Target: *.", + "inputSchema": { + "additionalProperties": false, + "properties": { + "body": { + "description": "Closing comment explaining why the issue is being closed and summarizing any resolution, workaround, or conclusion.", + "type": "string" + }, + "issue_number": { + "description": "Issue number to close. This is the numeric ID from the GitHub URL (e.g., 901 in github.com/owner/repo/issues/901). If omitted, closes the issue that triggered this workflow (requires an issue event trigger).", + "type": [ + "number", + "string" + ] + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "name": "close_issue" + }, + { + "description": "Add a comment to an existing GitHub issue, pull request, or discussion. Use this to provide feedback, answer questions, or add information to an existing conversation. For creating new items, use create_issue, create_discussion, or create_pull_request instead. IMPORTANT: Comments are subject to validation constraints enforced by the MCP server - maximum 65536 characters for the complete comment (including footer which is added automatically), 10 mentions (@username), and 50 links. Exceeding these limits will result in an immediate error with specific guidance. NOTE: By default, this tool requires discussions:write permission. If your GitHub App lacks Discussions permission, set 'discussions: false' in the workflow's safe-outputs.add-comment configuration to exclude this permission. CONSTRAINTS: Maximum 10 comment(s) can be added. Target: *.", + "inputSchema": { + "additionalProperties": false, + "properties": { + "body": { + "description": "The comment text in Markdown format. This is the 'body' field - do not use 'comment_body' or other variations. Provide helpful, relevant information that adds value to the conversation. CONSTRAINTS: The complete comment (your body text + automatically added footer) must not exceed 65536 characters total. Maximum 10 mentions (@username), maximum 50 links (http/https URLs). A footer (~200-500 characters) is automatically appended with workflow attribution, so leave adequate space. If these limits are exceeded, the tool call will fail with a detailed error message indicating which constraint was violated.", + "type": "string" + }, + "item_number": { + "description": "The issue, pull request, or discussion number to comment on. This is the numeric ID from the GitHub URL (e.g., 123 in github.com/owner/repo/issues/123). If omitted, the tool auto-targets the issue, PR, or discussion that triggered this workflow. Auto-targeting only works for issue, pull_request, discussion, and comment event triggers — it does NOT work for schedule, workflow_dispatch, push, or workflow_run triggers. For those trigger types, always provide item_number explicitly, or the comment will be silently discarded.", + "type": "number" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "name": "add_comment" + }, + { + "description": "Assign the GitHub Copilot coding agent to work on an issue or pull request. The agent will analyze the issue/PR and attempt to implement a solution, creating a pull request when complete. Use this to delegate coding tasks to Copilot. Example usage: assign_to_agent(issue_number=123, agent=\"copilot\") or assign_to_agent(pull_number=456, agent=\"copilot\", pull_request_repo=\"owner/repo\") CONSTRAINTS: Maximum 1 issue(s) can be assigned to agent.", + "inputSchema": { + "additionalProperties": false, + "properties": { + "agent": { + "description": "Agent identifier to assign. Defaults to 'copilot' (the Copilot coding agent) if not specified.", + "type": "string" + }, + "issue_number": { + "description": "Issue number to assign the Copilot coding agent to. This is the numeric ID from the GitHub URL (e.g., 234 in github.com/owner/repo/issues/234). Can also be a temporary_id (e.g., 'aw_abc123', 'aw_Test123') from an issue created earlier in the same workflow run. The issue should contain clear, actionable requirements. Either issue_number or pull_number must be provided, but not both.", + "type": [ + "number", + "string" + ] + }, + "pull_number": { + "description": "Pull request number to assign the Copilot coding agent to. This is the numeric ID from the GitHub URL (e.g., 456 in github.com/owner/repo/pull/456). Either issue_number or pull_number must be provided, but not both.", + "type": [ + "number", + "string" + ] + }, + "pull_request_repo": { + "description": "Target repository where the pull request should be created, in 'owner/repo' format. If omitted, the PR will be created in the same repository as the issue. This allows issues and code to live in different repositories. The global pull-request-repo configuration (if set) is automatically allowed; additional repositories must be listed in allowed-pull-request-repos.", + "type": "string" + } + }, + "type": "object" + }, + "name": "assign_to_agent" + }, + { + "description": "Report that a tool or capability needed to complete the task is not available, or share any information you deem important about missing functionality or limitations. Use this when you cannot accomplish what was requested because the required functionality is missing or access is restricted.", + "inputSchema": { + "additionalProperties": false, + "properties": { + "alternatives": { + "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).", + "type": "string" + }, + "reason": { + "description": "Explanation of why this tool is needed or what information you want to share about the limitation (max 256 characters).", + "type": "string" + }, + "tool": { + "description": "Optional: Name or description of the missing tool or capability (max 128 characters). Be specific about what functionality is needed.", + "type": "string" + } + }, + "required": [ + "reason" + ], + "type": "object" + }, + "name": "missing_tool" + }, + { + "description": "Log a transparency message when no significant actions are needed. Use this to confirm workflow completion and provide visibility when analysis is complete but no changes or outputs are required (e.g., 'No issues found', 'All checks passed'). This ensures the workflow produces human-visible output even when no other actions are taken.", + "inputSchema": { + "additionalProperties": false, + "properties": { + "message": { + "description": "Status or completion message to log. Should explain what was analyzed and the outcome (e.g., 'Code review complete - no issues found', 'Analysis complete - all tests passing').", + "type": "string" + } + }, + "required": [ + "message" + ], + "type": "object" + }, + "name": "noop" + }, + { + "description": "Report that data or information needed to complete the task is not available. Use this when you cannot accomplish what was requested because required data, context, or information is missing.", + "inputSchema": { + "additionalProperties": false, + "properties": { + "alternatives": { + "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).", + "type": "string" + }, + "context": { + "description": "Additional context about the missing data or where it should come from (max 256 characters).", + "type": "string" + }, + "data_type": { + "description": "Type or description of the missing data or information (max 128 characters). Be specific about what data is needed.", + "type": "string" + }, + "reason": { + "description": "Explanation of why this data is needed to complete the task (max 256 characters).", + "type": "string" + } + }, + "required": [], + "type": "object" + }, + "name": "missing_data" + } + ] + GH_AW_SAFE_OUTPUTS_TOOLS_EOF + cat > /opt/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_EOF' + { + "add_comment": { + "defaultMax": 1, + "fields": { + "body": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "item_number": { + "issueOrPRNumber": true + }, + "repo": { + "type": "string", + "maxLength": 256 + } + } + }, + "assign_to_agent": { + "defaultMax": 1, + "fields": { + "agent": { + "type": "string", + "sanitize": true, + "maxLength": 128 + }, + "issue_number": { + "issueNumberOrTemporaryId": true + }, + "pull_number": { + "optionalPositiveInteger": true + }, + "pull_request_repo": { + "type": "string", + "maxLength": 256 + }, + "repo": { + "type": "string", + "maxLength": 256 + } + }, + "customValidation": "requiresOneOf:issue_number,pull_number" + }, + "close_issue": { + "defaultMax": 1, + "fields": { + "body": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "issue_number": { + "optionalPositiveInteger": true + }, + "repo": { + "type": "string", + "maxLength": 256 + } + } + }, + "create_issue": { + "defaultMax": 1, + "fields": { + "body": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "labels": { + "type": "array", + "itemType": "string", + "itemSanitize": true, + "itemMaxLength": 128 + }, + "parent": { + "issueOrPRNumber": true + }, + "repo": { + "type": "string", + "maxLength": 256 + }, + "temporary_id": { + "type": "string" + }, + "title": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 128 + } + } + }, + "missing_data": { + "defaultMax": 20, + "fields": { + "alternatives": { + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "context": { + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "data_type": { + "type": "string", + "sanitize": true, + "maxLength": 128 + }, + "reason": { + "type": "string", + "sanitize": true, + "maxLength": 256 + } + } + }, + "missing_tool": { + "defaultMax": 20, + "fields": { + "alternatives": { + "type": "string", + "sanitize": true, + "maxLength": 512 + }, + "reason": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "tool": { + "type": "string", + "sanitize": true, + "maxLength": 128 + } + } + }, + "noop": { + "defaultMax": 1, + "fields": { + "message": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + } + } + } + } + GH_AW_SAFE_OUTPUTS_VALIDATION_EOF + - name: Generate Safe Outputs MCP Server Config + id: safe-outputs-config + run: | + # Generate a secure random API key (360 bits of entropy, 40+ chars) + # Mask immediately to prevent timing vulnerabilities + API_KEY=$(openssl rand -base64 45 | tr -d '/+=') + echo "::add-mask::${API_KEY}" + + PORT=3001 + + # Set outputs for next steps + { + echo "safe_outputs_api_key=${API_KEY}" + echo "safe_outputs_port=${PORT}" + } >> "$GITHUB_OUTPUT" + + echo "Safe Outputs MCP server will run on port ${PORT}" + + - name: Start Safe Outputs MCP HTTP Server + id: safe-outputs-start + env: + DEBUG: '*' + GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }} + GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }} + GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json + GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json + GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs + run: | + # Environment variables are set above to prevent template injection + export DEBUG + export GH_AW_SAFE_OUTPUTS_PORT + export GH_AW_SAFE_OUTPUTS_API_KEY + export GH_AW_SAFE_OUTPUTS_TOOLS_PATH + export GH_AW_SAFE_OUTPUTS_CONFIG_PATH + export GH_AW_MCP_LOG_DIR + + bash /opt/gh-aw/actions/start_safe_outputs_server.sh + + - name: Start MCP Gateway + id: start-mcp-gateway + env: + GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} + GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }} + GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }} + GITHUB_MCP_LOCKDOWN: ${{ steps.determine-automatic-lockdown.outputs.lockdown == 'true' && '1' || '0' }} + GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + run: | + set -eo pipefail + mkdir -p /tmp/gh-aw/mcp-config + + # Export gateway environment variables for MCP config and gateway script + export MCP_GATEWAY_PORT="80" + export MCP_GATEWAY_DOMAIN="host.docker.internal" + MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=') + echo "::add-mask::${MCP_GATEWAY_API_KEY}" + export MCP_GATEWAY_API_KEY + export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads" + mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}" + export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288" + export DEBUG="*" + + export GH_AW_ENGINE="copilot" + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_LOCKDOWN -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.1.6' + + mkdir -p /home/runner/.copilot + cat << GH_AW_MCP_CONFIG_EOF | bash /opt/gh-aw/actions/start_mcp_gateway.sh + { + "mcpServers": { + "github": { + "type": "stdio", + "container": "ghcr.io/github/github-mcp-server:v0.31.0", + "env": { + "GITHUB_LOCKDOWN_MODE": "$GITHUB_MCP_LOCKDOWN", + "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", + "GITHUB_READ_ONLY": "1", + "GITHUB_TOOLSETS": "context,repos,issues" + } + }, + "safeoutputs": { + "type": "http", + "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT", + "headers": { + "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}" + } + } + }, + "gateway": { + "port": $MCP_GATEWAY_PORT, + "domain": "${MCP_GATEWAY_DOMAIN}", + "apiKey": "${MCP_GATEWAY_API_KEY}", + "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" + } + } + GH_AW_MCP_CONFIG_EOF + - name: Download activation artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: activation + path: /tmp/gh-aw + - name: Clean git credentials + run: bash /opt/gh-aw/actions/clean_git_credentials.sh + - name: Execute GitHub Copilot CLI + id: agentic_execution + # Copilot CLI tool arguments (sorted): + timeout-minutes: 20 + run: | + set -o pipefail + # shellcheck disable=SC1003 + sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \ + -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"}' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + env: + COPILOT_AGENT_RUNNER_TYPE: STANDALONE + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json + GH_AW_MODEL_AGENT_COPILOT: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} + GITHUB_API_URL: ${{ github.api_url }} + GITHUB_HEAD_REF: ${{ github.head_ref }} + GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + GITHUB_REF_NAME: ${{ github.ref_name }} + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} + GITHUB_WORKSPACE: ${{ github.workspace }} + XDG_CONFIG_HOME: /home/runner + - name: Configure Git credentials + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + git config --global am.keepcr true + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" + - name: Copy Copilot session state files to logs + if: always() + continue-on-error: true + run: | + # Copy Copilot session state files to logs folder for artifact collection + # This ensures they are in /tmp/gh-aw/ where secret redaction can scan them + SESSION_STATE_DIR="$HOME/.copilot/session-state" + LOGS_DIR="/tmp/gh-aw/sandbox/agent/logs" + + if [ -d "$SESSION_STATE_DIR" ]; then + echo "Copying Copilot session state files from $SESSION_STATE_DIR to $LOGS_DIR" + mkdir -p "$LOGS_DIR" + cp -v "$SESSION_STATE_DIR"/*.jsonl "$LOGS_DIR/" 2>/dev/null || true + echo "Session state files copied successfully" + else + echo "No session-state directory found at $SESSION_STATE_DIR" + fi + - name: Stop MCP Gateway + if: always() + continue-on-error: true + env: + MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }} + MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }} + GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }} + run: | + bash /opt/gh-aw/actions/stop_mcp_gateway.sh "$GATEWAY_PID" + - name: Redact secrets in logs + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + with: + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('/opt/gh-aw/actions/redact_secrets.cjs'); + await main(); + env: + GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' + SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} + SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} + SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Upload Safe Outputs + if: always() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: safe-output + path: ${{ env.GH_AW_SAFE_OUTPUTS }} + if-no-files-found: warn + - name: Ingest agent output + id: collect_output + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_API_URL: ${{ github.api_url }} + with: + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('/opt/gh-aw/actions/collect_ndjson_output.cjs'); + await main(); + - name: Upload sanitized agent output + if: always() && env.GH_AW_AGENT_OUTPUT + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: agent-output + path: ${{ env.GH_AW_AGENT_OUTPUT }} + if-no-files-found: warn + - name: Upload engine output files + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: agent_outputs + path: | + /tmp/gh-aw/sandbox/agent/logs/ + /tmp/gh-aw/redacted-urls.log + if-no-files-found: ignore + - name: Parse agent logs for step summary + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/ + with: + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('/opt/gh-aw/actions/parse_copilot_log.cjs'); + await main(); + - name: Parse MCP Gateway logs for step summary + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + with: + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('/opt/gh-aw/actions/parse_mcp_gateway_log.cjs'); + await main(); + - name: Print firewall logs + if: always() + continue-on-error: true + env: + AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs + run: | + # Fix permissions on firewall logs so they can be uploaded as artifacts + # AWF runs with sudo, creating files owned by root + sudo chmod -R a+r /tmp/gh-aw/sandbox/firewall/logs 2>/dev/null || true + # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step) + if command -v awf &> /dev/null; then + awf logs summary | tee -a "$GITHUB_STEP_SUMMARY" + else + echo 'AWF binary not installed, skipping firewall log summary' + fi + - name: Upload agent artifacts + if: always() + continue-on-error: true + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: agent-artifacts + path: | + /tmp/gh-aw/aw-prompts/prompt.txt + /tmp/gh-aw/mcp-logs/ + /tmp/gh-aw/sandbox/firewall/logs/ + /tmp/gh-aw/agent-stdio.log + /tmp/gh-aw/agent/ + if-no-files-found: ignore + # --- Threat Detection (inline) --- + - name: Check if detection needed + id: detection_guard + if: always() + env: + OUTPUT_TYPES: ${{ steps.collect_output.outputs.output_types }} + HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }} + run: | + if [[ -n "$OUTPUT_TYPES" || "$HAS_PATCH" == "true" ]]; then + echo "run_detection=true" >> "$GITHUB_OUTPUT" + echo "Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH" + else + echo "run_detection=false" >> "$GITHUB_OUTPUT" + echo "Detection skipped: no agent outputs or patches to analyze" + fi + - name: Clear MCP configuration for detection + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + rm -f /tmp/gh-aw/mcp-config/mcp-servers.json + rm -f /home/runner/.copilot/mcp-config.json + rm -f "$GITHUB_WORKSPACE/.gemini/settings.json" + - name: Prepare threat detection files + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + mkdir -p /tmp/gh-aw/threat-detection/aw-prompts + cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true + cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true + for f in /tmp/gh-aw/aw-*.patch; do + [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true + done + echo "Prepared threat detection files:" + ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true + - name: Setup threat detection + if: always() && steps.detection_guard.outputs.run_detection == 'true' + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + WORKFLOW_NAME: "Weekly Reference Implementation Sync Agentic Workflow" + WORKFLOW_DESCRIPTION: "Weekly reference implementation sync workflow. Checks for new commits in the official\nCopilot SDK (github/copilot-sdk) and assigns to Copilot to port changes." + HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }} + with: + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('/opt/gh-aw/actions/setup_threat_detection.cjs'); + await main(); + - name: Ensure threat-detection directory and log + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + mkdir -p /tmp/gh-aw/threat-detection + touch /tmp/gh-aw/threat-detection/detection.log + - name: Execute GitHub Copilot CLI + if: always() && steps.detection_guard.outputs.run_detection == 'true' + id: detection_agentic_execution + # Copilot CLI tool arguments (sorted): + # --allow-tool shell(cat) + # --allow-tool shell(grep) + # --allow-tool shell(head) + # --allow-tool shell(jq) + # --allow-tool shell(ls) + # --allow-tool shell(tail) + # --allow-tool shell(wc) + timeout-minutes: 20 + run: | + set -o pipefail + # shellcheck disable=SC1003 + sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,raw.githubusercontent.com,registry.npmjs.org,telemetry.enterprise.githubcopilot.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \ + -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(wc)'\'' --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_DETECTION_COPILOT:+ --model "$GH_AW_MODEL_DETECTION_COPILOT"}' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + env: + COPILOT_AGENT_RUNNER_TYPE: STANDALONE + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + GH_AW_MODEL_DETECTION_COPILOT: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }} + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GITHUB_API_URL: ${{ github.api_url }} + GITHUB_HEAD_REF: ${{ github.head_ref }} + GITHUB_REF_NAME: ${{ github.ref_name }} + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} + GITHUB_WORKSPACE: ${{ github.workspace }} + XDG_CONFIG_HOME: /home/runner + - name: Parse threat detection results + id: parse_detection_results + if: always() && steps.detection_guard.outputs.run_detection == 'true' + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + with: + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('/opt/gh-aw/actions/parse_threat_detection_results.cjs'); + await main(); + - name: Upload threat detection log + if: always() && steps.detection_guard.outputs.run_detection == 'true' + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: threat-detection.log + path: /tmp/gh-aw/threat-detection/detection.log + if-no-files-found: ignore + - name: Set detection conclusion + id: detection_conclusion + if: always() + env: + RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }} + DETECTION_SUCCESS: ${{ steps.parse_detection_results.outputs.success }} + run: | + if [[ "$RUN_DETECTION" != "true" ]]; then + echo "conclusion=skipped" >> "$GITHUB_OUTPUT" + echo "success=true" >> "$GITHUB_OUTPUT" + echo "Detection was not needed, marking as skipped" + elif [[ "$DETECTION_SUCCESS" == "true" ]]; then + echo "conclusion=success" >> "$GITHUB_OUTPUT" + echo "success=true" >> "$GITHUB_OUTPUT" + echo "Detection passed successfully" + else + echo "conclusion=failure" >> "$GITHUB_OUTPUT" + echo "success=false" >> "$GITHUB_OUTPUT" + echo "Detection found issues" + fi + + conclusion: + needs: + - activation + - agent + - safe_outputs + if: (always()) && (needs.agent.result != 'skipped') + runs-on: ubuntu-slim + permissions: + contents: read + discussions: write + issues: write + pull-requests: write + outputs: + noop_message: ${{ steps.noop.outputs.noop_message }} + tools_reported: ${{ steps.missing_tool.outputs.tools_reported }} + total_count: ${{ steps.missing_tool.outputs.total_count }} + steps: + - name: Setup Scripts + uses: github/gh-aw/actions/setup@33cd6c7f1fee588654ef19def2e6a4174be66197 # v0.51.6 + with: + destination: /opt/gh-aw/actions + - name: Download agent output artifact + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: agent-output + path: /tmp/gh-aw/safeoutputs/ + - name: Setup agent output environment variable + run: | + mkdir -p /tmp/gh-aw/safeoutputs/ + find "/tmp/gh-aw/safeoutputs/" -type f -print + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Process No-Op Messages + id: noop + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} + GH_AW_NOOP_MAX: "1" + GH_AW_WORKFLOW_NAME: "Weekly Reference Implementation Sync Agentic Workflow" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('/opt/gh-aw/actions/noop.cjs'); + await main(); + - name: Record Missing Tool + id: missing_tool + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Weekly Reference Implementation Sync Agentic Workflow" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('/opt/gh-aw/actions/missing_tool.cjs'); + await main(); + - name: Handle Agent Failure + id: handle_agent_failure + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Weekly Reference Implementation Sync Agentic Workflow" + GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} + GH_AW_WORKFLOW_ID: "weekly-reference-impl-sync" + GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} + GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} + GH_AW_ASSIGNMENT_ERRORS: ${{ needs.safe_outputs.outputs.assign_to_agent_assignment_errors }} + GH_AW_ASSIGNMENT_ERROR_COUNT: ${{ needs.safe_outputs.outputs.assign_to_agent_assignment_error_count }} + GH_AW_GROUP_REPORTS: "false" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('/opt/gh-aw/actions/handle_agent_failure.cjs'); + await main(); + - name: Handle No-Op Message + id: handle_noop_message + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Weekly Reference Implementation Sync Agentic Workflow" + GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} + GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }} + GH_AW_NOOP_REPORT_AS_ISSUE: "false" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('/opt/gh-aw/actions/handle_noop_message.cjs'); + await main(); + + safe_outputs: + needs: agent + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.agent.outputs.detection_success == 'true') + runs-on: ubuntu-slim + permissions: + contents: read + discussions: write + issues: write + pull-requests: write + timeout-minutes: 15 + env: + GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/${{ github.workflow }}" + GH_AW_ENGINE_ID: "copilot" + GH_AW_WORKFLOW_ID: "weekly-reference-impl-sync" + GH_AW_WORKFLOW_NAME: "Weekly Reference Implementation Sync Agentic Workflow" + outputs: + assign_to_agent_assigned: ${{ steps.assign_to_agent.outputs.assigned }} + assign_to_agent_assignment_error_count: ${{ steps.assign_to_agent.outputs.assignment_error_count }} + assign_to_agent_assignment_errors: ${{ steps.assign_to_agent.outputs.assignment_errors }} + code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }} + code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }} + comment_id: ${{ steps.process_safe_outputs.outputs.comment_id }} + comment_url: ${{ steps.process_safe_outputs.outputs.comment_url }} + create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }} + create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }} + created_issue_number: ${{ steps.process_safe_outputs.outputs.created_issue_number }} + created_issue_url: ${{ steps.process_safe_outputs.outputs.created_issue_url }} + process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }} + process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} + steps: + - name: Setup Scripts + uses: github/gh-aw/actions/setup@33cd6c7f1fee588654ef19def2e6a4174be66197 # v0.51.6 + with: + destination: /opt/gh-aw/actions + - name: Download agent output artifact + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: agent-output + path: /tmp/gh-aw/safeoutputs/ + - name: Setup agent output environment variable + run: | + mkdir -p /tmp/gh-aw/safeoutputs/ + find "/tmp/gh-aw/safeoutputs/" -type f -print + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Process Safe Outputs + id: process_safe_outputs + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_API_URL: ${{ github.api_url }} + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":10,\"target\":\"*\"},\"close_issue\":{\"max\":10,\"required_labels\":[\"reference-impl-sync\"],\"target\":\"*\"},\"create_issue\":{\"assignees\":[\"copilot\"],\"expires\":144,\"labels\":[\"reference-impl-sync\"],\"max\":1,\"title_prefix\":\"[reference-impl-sync] \"},\"missing_data\":{},\"missing_tool\":{}}" + GH_AW_ASSIGN_COPILOT: "true" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('/opt/gh-aw/actions/safe_output_handler_manager.cjs'); + await main(); + - name: Assign Copilot to created issues + if: steps.process_safe_outputs.outputs.issues_to_assign_copilot != '' + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_ISSUES_TO_ASSIGN_COPILOT: ${{ steps.process_safe_outputs.outputs.issues_to_assign_copilot }} + with: + github-token: ${{ secrets.GH_AW_AGENT_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('/opt/gh-aw/actions/assign_copilot_to_created_issues.cjs'); + await main(); + - name: Assign to agent + id: assign_to_agent + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'assign_to_agent')) + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} + GH_AW_AGENT_MAX_COUNT: 1 + GH_AW_AGENT_DEFAULT: "copilot" + GH_AW_AGENT_DEFAULT_MODEL: "claude-opus-4.6" + GH_AW_AGENT_TARGET: "*" + GH_AW_TEMPORARY_ID_MAP: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} + with: + github-token: ${{ secrets.GH_AW_AGENT_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('/opt/gh-aw/actions/assign_to_agent.cjs'); + await main(); + - name: Upload safe output items manifest + if: always() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: safe-output-items + path: /tmp/safe-output-items.jsonl + if-no-files-found: warn + diff --git a/.github/workflows/weekly-reference-impl-sync.md b/.github/workflows/weekly-reference-impl-sync.md new file mode 100644 index 000000000..7e72248e1 --- /dev/null +++ b/.github/workflows/weekly-reference-impl-sync.md @@ -0,0 +1,151 @@ +--- +description: | + Weekly reference implementation sync workflow. Checks for new commits in the official + Copilot SDK (github/copilot-sdk) and assigns to Copilot to port changes. + +on: + schedule: weekly + workflow_dispatch: + +permissions: + contents: read + actions: read + issues: read + +network: + allowed: + - defaults + - github + +tools: + github: + toolsets: [context, repos, issues] + +safe-outputs: + create-issue: + title-prefix: "[reference-impl-sync] " + assignees: [copilot] + labels: [reference-impl-sync] + expires: 6 + close-issue: + required-labels: [reference-impl-sync] + target: "*" + max: 10 + add-comment: + target: "*" + max: 10 + assign-to-agent: + name: "copilot" + model: "claude-opus-4.6" + target: "*" + noop: + report-as-issue: false +--- +# Weekly Reference Implementation Sync Agentic Workflow +This document describes the `weekly-reference-impl-sync.yml` GitHub Actions workflow, which automates the detection of new changes in the official [Copilot SDK](https://github.com/github/copilot-sdk) and delegates the merge work to the Copilot coding agent. + +## Overview + +The workflow runs on a **weekly schedule** (every Monday at 10:00 UTC) and can also be triggered manually. It does **not** perform the actual merge — instead, it detects reference implementation changes and creates a GitHub issue assigned to `copilot`, instructing the agent to follow the [agentic-merge-reference-impl](../prompts/agentic-merge-reference-impl.prompt.md) prompt to port the changes. + +The agent must also create the Pull Request with the label `reference-impl-sync`. This allows the workflow to track the merge progress and avoid creating duplicate issues if the agent is still working on a previous sync. + +## Trigger + +| Trigger | Schedule | +|---|---| +| `schedule` | Every Monday at 10:00 UTC (`0 10 * * 1`) | +| `workflow_dispatch` | Manual trigger from the Actions tab | + +## Workflow Steps + +### 1. Checkout repository + +Checks out the repo to read the `.lastmerge` file, which contains the SHA of the last reference implementation commit that was merged into the Java SDK. + +### 2. Check for reference implementation changes + +- Reads the last merged commit hash from `.lastmerge` +- Clones the reference implementation `github/copilot-sdk` repository +- Compares `.lastmerge` against reference implementation `HEAD` +- If they match: sets `has_changes=false` +- If they differ: counts new commits, generates a summary (up to 20 most recent), and sets outputs (`commit_count`, `reference_impl_head`, `last_merge`, `summary`) + +### 3. Close previous reference-impl-sync issues (when changes found) + +**Condition:** `has_changes == true` + +Before creating a new issue, closes any existing open issues with the `reference-impl-sync` label. This prevents stale issues from accumulating when previous sync attempts were incomplete or superseded. Each closed issue receives a comment explaining it was superseded. + +### 4. Close stale reference-impl-sync issues (when no changes found) + +**Condition:** `has_changes == false` + +If the reference implementation is already up to date, closes any lingering open `reference-impl-sync` issues with a comment noting that no changes were detected. This handles the case where a previous issue was created but the changes were merged manually (updating `.lastmerge`) before the agent completed. + +### 5. Create issue and assign to Copilot + +**Condition:** `has_changes == true` + +Creates a new GitHub issue with: + +- **Title:** `Reference implementation sync: N new commits (YYYY-MM-DD)` +- **Label:** `reference-impl-sync` +- **Assignee:** `copilot` +- **Body:** Contains commit count, commit range links, a summary of recent commits, and a link to the merge prompt + +The Copilot coding agent picks up the issue, creates a branch and PR, then follows the merge prompt to port the changes. + +### 6. Summary + +Writes a GitHub Actions step summary with: + +- Whether changes were detected +- Commit count and range +- Recent reference implementation commits +- Link to the created issue (if any) + +## Flow Diagram + +``` +┌─────────────────────┐ +│ Schedule / Manual │ +└──────────┬──────────┘ + │ + ▼ +┌──────────────────────────┐ +│ Read .lastmerge │ +│ Clone reference impl SDK │ +│ Compare commits │ +└──────────┬───────────────┘ + │ + ┌─────┴─────┐ + │ │ + changes? no changes + │ │ + ▼ ▼ +┌──────────┐ ┌──────────────────┐ +│ Close old│ │ Close stale │ +│ issues │ │ issues │ +└────┬─────┘ └──────────────────┘ + │ + ▼ +┌──────────────────────────┐ +│ Create issue assigned to │ +│ copilot │ +└──────────────────────────┘ + │ + ▼ +┌──────────────────────────┐ +│ Agent follows prompt to │ +│ port changes → PR │ +└──────────────────────────┘ +``` + +## Related Files + +| File | Purpose | +|---|---| +| `.lastmerge` | Stores the SHA of the last merged reference implementation commit | +| [agentic-merge-reference-impl.prompt.md](../prompts/agentic-merge-reference-impl.prompt.md) | Detailed instructions the Copilot agent follows to port changes | +| `.github/scripts/reference-impl-sync/` | Helper scripts used by the merge prompt | diff --git a/.github/workflows/weekly-reference-impl-sync.yml b/.github/workflows/weekly-reference-impl-sync.yml new file mode 100644 index 000000000..aa3fc971a --- /dev/null +++ b/.github/workflows/weekly-reference-impl-sync.yml @@ -0,0 +1,181 @@ +name: "Weekly Reference Implementation Sync" + +on: + schedule: + # Every Monday at 10:00 UTC (5:00 AM EST / 6:00 AM EDT) + - cron: '0 10 * * 1' + workflow_dispatch: + +permissions: + contents: write + issues: write + pull-requests: write + +env: + # Used for `gh` CLI operations to create/close/comment issues. Must be a PAT with repo permissions because the default + GH_AW_AGENT_TOKEN: ${{ secrets.GH_AW_AGENT_TOKEN }} + GH_TOKEN: ${{ secrets.GH_AW_AGENT_TOKEN }} + +jobs: + + check-and-sync: + name: "Check reference implementation & trigger Copilot merge" + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Check for reference implementation changes + id: check + run: | + LAST_MERGE=$(cat .lastmerge) + echo "Last merged commit: $LAST_MERGE" + + git clone --quiet https://github.com/github/copilot-sdk.git /tmp/reference-impl + cd /tmp/reference-impl + + REFERENCE_IMPL_HEAD=$(git rev-parse HEAD) + echo "Reference implementation HEAD: $REFERENCE_IMPL_HEAD" + + echo "last_merge=$LAST_MERGE" >> "$GITHUB_OUTPUT" + + if [ "$LAST_MERGE" = "$REFERENCE_IMPL_HEAD" ]; then + echo "No new reference implementation changes since last merge." + echo "has_changes=false" >> "$GITHUB_OUTPUT" + else + COMMIT_COUNT=$(git rev-list --count "$LAST_MERGE".."$REFERENCE_IMPL_HEAD") + echo "Found $COMMIT_COUNT new reference implementation commits." + echo "has_changes=true" >> "$GITHUB_OUTPUT" + echo "commit_count=$COMMIT_COUNT" >> "$GITHUB_OUTPUT" + echo "reference_impl_head=$REFERENCE_IMPL_HEAD" >> "$GITHUB_OUTPUT" + + # Generate a short summary of changes + SUMMARY=$(git log --oneline "$LAST_MERGE".."$REFERENCE_IMPL_HEAD" | head -20) + { + echo "summary<> "$GITHUB_OUTPUT" + fi + + - name: Close previous reference-impl-sync issues + if: steps.check.outputs.has_changes == 'true' + run: | + # Find all open issues with the reference-impl-sync label + OPEN_ISSUES=$(gh issue list \ + --repo "${{ github.repository }}" \ + --label "reference-impl-sync" \ + --state open \ + --json number \ + --jq '.[].number') + + for ISSUE_NUM in $OPEN_ISSUES; do + echo "Closing superseded issue #${ISSUE_NUM}" + gh issue comment "$ISSUE_NUM" \ + --repo "${{ github.repository }}" \ + --body "Superseded by a newer reference implementation sync issue. Closing this one." + gh issue close "$ISSUE_NUM" \ + --repo "${{ github.repository }}" \ + --reason "not planned" + done + + - name: Close stale reference-impl-sync issues (no changes) + if: steps.check.outputs.has_changes == 'false' + run: | + OPEN_ISSUES=$(gh issue list \ + --repo "${{ github.repository }}" \ + --label "reference-impl-sync" \ + --state open \ + --json number \ + --jq '.[].number') + + for ISSUE_NUM in $OPEN_ISSUES; do + echo "Closing stale issue #${ISSUE_NUM} — reference implementation is up to date" + gh issue comment "$ISSUE_NUM" \ + --repo "${{ github.repository }}" \ + --body "No new reference implementation changes detected. The Java SDK is up to date. Closing." + gh issue close "$ISSUE_NUM" \ + --repo "${{ github.repository }}" \ + --reason "completed" + done + + - name: Create issue and assign to Copilot + id: create-issue + if: steps.check.outputs.has_changes == 'true' + env: + SUMMARY: ${{ steps.check.outputs.summary }} + run: | + COMMIT_COUNT="${{ steps.check.outputs.commit_count }}" + LAST_MERGE="${{ steps.check.outputs.last_merge }}" + REFERENCE_IMPL_HEAD="${{ steps.check.outputs.reference_impl_head }}" + DATE=$(date -u +"%Y-%m-%d") + REPO="${{ github.repository }}" + + BODY="## Automated Reference Implementation Sync + + There are **${COMMIT_COUNT}** new commits in the [official Copilot SDK](https://github.com/github/copilot-sdk) since the last merge. + + - **Last merged commit:** [\`${LAST_MERGE}\`](https://github.com/github/copilot-sdk/commit/${LAST_MERGE}) + - **Reference implementation HEAD:** [\`${REFERENCE_IMPL_HEAD}\`](https://github.com/github/copilot-sdk/commit/${REFERENCE_IMPL_HEAD}) + + ### Recent reference implementation commits + + \`\`\` + ${SUMMARY} + \`\`\` + + ### Instructions + + Follow the [agentic-merge-reference-impl](.github/prompts/agentic-merge-reference-impl.prompt.md) prompt to port these changes to the Java SDK." + + # Create the issue and assign to Copilot coding agent + ISSUE_URL=$(gh issue create \ + --repo "$REPO" \ + --title "Reference implementation sync: ${COMMIT_COUNT} new commits (${DATE})" \ + --body "$BODY" \ + --label "reference-impl-sync" \ + --assignee "copilot-swe-agent") + + echo "issue_url=$ISSUE_URL" >> "$GITHUB_OUTPUT" + echo "✅ Issue created and assigned to Copilot coding agent: $ISSUE_URL" + + - name: Summary + if: always() + env: + SUMMARY: ${{ steps.check.outputs.summary }} + run: | + HAS_CHANGES="${{ steps.check.outputs.has_changes }}" + COMMIT_COUNT="${{ steps.check.outputs.commit_count }}" + LAST_MERGE="${{ steps.check.outputs.last_merge }}" + REFERENCE_IMPL_HEAD="${{ steps.check.outputs.reference_impl_head }}" + ISSUE_URL="${{ steps.create-issue.outputs.issue_url }}" + + { + echo "## Weekly Reference Implementation Sync" + echo "" + if [ "$HAS_CHANGES" = "true" ]; then + echo "### ✅ New reference implementation changes detected" + echo "" + echo "| | |" + echo "|---|---|" + echo "| **New commits** | ${COMMIT_COUNT} |" + echo "| **Last merged** | \`${LAST_MERGE:0:12}\` |" + echo "| **Reference implementation HEAD** | \`${REFERENCE_IMPL_HEAD:0:12}\` |" + echo "" + echo "An issue has been created and assigned to the Copilot coding agent: " + echo " -> ${ISSUE_URL}" + echo "" + echo "### Recent reference implementation commits" + echo "" + echo '```' + echo "$SUMMARY" + echo '```' + else + echo "### ⏭️ No changes" + echo "" + echo "The Java SDK is already up to date with the reference implementation Copilot SDK." + echo "" + echo "**Last merged commit:** \`${LAST_MERGE:0:12}\`" + fi + } >> "$GITHUB_STEP_SUMMARY" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b9320ee1a..6c85671bf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,7 +19,7 @@ We'd love your help with: * Making the SDK more idiomatic and nice to use for Java developers * Improving documentation -If you have ideas for entirely new features, please post an issue or start a discussion. We're very open to new features but need to make sure they align with the direction of the upstream [Copilot SDK](https://github.com/github/copilot-sdk) and can be maintained in sync. Note that this repo periodically merges upstream changes — see the [README](README.md#agentic-upstream-merge-and-sync) for details on how that works. +If you have ideas for entirely new features, please post an issue or start a discussion. We're very open to new features but need to make sure they align with the direction of the [Copilot SDK](https://github.com/github/copilot-sdk) reference implementation and can be maintained in sync. Note that this repo periodically merges reference implementation changes — see the [README](README.md#agentic-reference-implementation-merge-and-sync) for details on how that works. ## Prerequisites for running and testing code diff --git a/README.md b/README.md index a33aaedda..34c04ace7 100644 --- a/README.md +++ b/README.md @@ -161,14 +161,14 @@ See [WORKFLOWS.md](docs/WORKFLOWS.md) for a full overview and details on each wo Contributions are welcome! Please see the [Contributing Guide](CONTRIBUTING.md) for details. -### Agentic Upstream Merge and Sync +### Agentic Reference Implementation Merge and Sync -This SDK tracks the official [Copilot SDK](https://github.com/github/copilot-sdk) (.NET reference implementation) and ports changes to Java. The upstream merge process is automated with AI assistance: +This SDK tracks the official [Copilot SDK](https://github.com/github/copilot-sdk) (.NET reference implementation) and ports changes to Java. The reference implementation merge process is automated with AI assistance: -**Weekly automated sync** — A [scheduled GitHub Actions workflow](.github/workflows/weekly-upstream-sync.yml) runs every Monday at 5 AM ET. It checks for new upstream commits since the last merge (tracked in [`.lastmerge`](.lastmerge)), and if changes are found, creates an issue labeled `upstream-sync` and assigns it to the GitHub Copilot coding agent. Any previously open `upstream-sync` issues are automatically closed. +**Weekly automated sync** — A [scheduled GitHub Actions workflow](.github/workflows/weekly-reference-impl-sync.yml) runs every Monday at 5 AM ET. It checks for new reference implementation commits since the last merge (tracked in [`.lastmerge`](.lastmerge)), and if changes are found, creates an issue labeled `reference-impl-sync` and assigns it to the GitHub Copilot coding agent. Any previously open `reference-impl-sync` issues are automatically closed. -**Reusable prompt** — The merge workflow is defined in [`agentic-merge-upstream.prompt.md`](.github/prompts/agentic-merge-upstream.prompt.md). It can be triggered manually from: -- **VS Code Copilot Chat** — type `/agentic-merge-upstream` +**Reusable prompt** — The merge workflow is defined in [`agentic-merge-reference-impl.prompt.md`](.github/prompts/agentic-merge-reference-impl.prompt.md). It can be triggered manually from: +- **VS Code Copilot Chat** — type `/agentic-merge-reference-impl` - **GitHub Copilot CLI** — use `copilot` CLI with the same skill reference ### Development Setup diff --git a/docs/WORKFLOWS.md b/docs/WORKFLOWS.md index 74afbd337..57ec34f71 100644 --- a/docs/WORKFLOWS.md +++ b/docs/WORKFLOWS.md @@ -7,8 +7,8 @@ | [Build & Test](workflows/build-test.yml) | Builds, lints, and tests the Java SDK | `push` (main), `pull_request`, `merge_group`, `workflow_dispatch` | Sundays at 00:00 UTC | | [Deploy Documentation](workflows/deploy-site.yml) | Generates and deploys versioned docs to GitHub Pages | `workflow_run` (after Build & Test), `release`, `workflow_dispatch` | — | | [Publish to Maven Central](workflows/publish-maven.yml) | Releases the SDK to Maven Central and creates a GitHub Release | `workflow_dispatch` | — | -| [Weekly Upstream Sync](workflows/weekly-upstream-sync.yml) | Checks for new upstream commits and creates an issue for Copilot to merge | `workflow_dispatch` | Mondays at 10:00 UTC | -| [Weekly Upstream Sync (Agentic)](workflows/weekly-upstream-sync.lock.yml) | Compiled agentic workflow that executes the upstream sync via `gh-aw` | `workflow_dispatch` | Tuesdays at 08:39 UTC (scattered) | +| [Weekly Reference Implementation Sync](workflows/weekly-reference-impl-sync.yml) | Checks for new reference implementation commits and creates an issue for Copilot to merge | `workflow_dispatch` | Mondays at 10:00 UTC | +| [Weekly Reference Implementation Sync (Agentic)](workflows/weekly-reference-impl-sync.lock.yml) | Compiled agentic workflow that executes the reference implementation sync via `gh-aw` | `workflow_dispatch` | Tuesdays at 08:39 UTC (scattered) | | [Copilot Setup Steps](workflows/copilot-setup-steps.yml) | Configures the environment for the GitHub Copilot coding agent | `push` (on self-change), `workflow_dispatch` | — | --- @@ -53,7 +53,7 @@ Manual-only workflow that performs a full release: 1. Determines release and next development versions (auto-derived from `pom.xml` or manually specified) 2. Updates `CHANGELOG.md`, `README.md`, and `jbang-example.java` with the release version -3. Injects the upstream sync commit hash from `.lastmerge` into the changelog +3. Injects the reference implementation sync commit hash from `.lastmerge` into the changelog 4. Runs `mvn release:prepare` and `mvn release:perform` to deploy to Maven Central 5. Creates a GitHub Release with auto-generated notes 6. Moves the `latest` git tag forward @@ -62,26 +62,26 @@ Manual-only workflow that performs a full release: --- -## Weekly Upstream Sync +## Weekly Reference Implementation Sync -**File:** [`weekly-upstream-sync.yml`](workflows/weekly-upstream-sync.yml) +**File:** [`weekly-reference-impl-sync.yml`](workflows/weekly-reference-impl-sync.yml) Runs every Monday at 10:00 UTC. Clones the official `github/copilot-sdk` repository and compares `HEAD` against the commit hash stored in `.lastmerge`. If new commits are found: -1. Closes any previously open `upstream-sync` issues -2. Creates a new issue with a summary of upstream changes +1. Closes any previously open `reference-impl-sync` issues +2. Creates a new issue with a summary of reference implementation changes 3. Assigns the issue to `copilot-swe-agent` for automated porting -If no changes are found, any stale open `upstream-sync` issues are closed. +If no changes are found, any stale open `reference-impl-sync` issues are closed. --- -## Weekly Upstream Sync (Agentic Workflow: Experimental) +## Weekly Reference Implementation Sync (Agentic Workflow: Experimental) -**File:** [`weekly-upstream-sync.lock.yml`](workflows/weekly-upstream-sync.lock.yml) +**File:** [`weekly-reference-impl-sync.lock.yml`](workflows/weekly-reference-impl-sync.lock.yml) -Auto-generated compiled workflow produced by `gh aw compile` from the corresponding `.md` source. This is the agentic counterpart that actually executes the upstream merge using the `gh-aw` MCP server and Copilot coding agent. +Auto-generated compiled workflow produced by `gh aw compile` from the corresponding `.md` source. This is the agentic counterpart that actually executes the reference implementation merge using the `gh-aw` MCP server and Copilot coding agent. > **Do not edit this file directly.** Edit the `.md` source and run `gh aw compile`. From 7de4b86aa2e32174fea78b04a77fce1f0165566a Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Thu, 16 Apr 2026 15:11:00 -0400 Subject: [PATCH 71/80] Replace upstream terminology with reference implementation Rebase the topic branch onto current main and preserve the original intent: replace "upstream" naming with "reference implementation" across the repo. - Update docs, prompts, workflows, and release automation wording - Remove legacy upstream-sync assets superseded by reference-impl-sync assets - Update references in tests and project guidance content - Keep behavior aligned while clarifying terminology - Apply Spotless formatting updates in touched Java test files --- .../skills/agentic-merge-upstream/SKILL.md | 7 - .github/copilot-instructions.md | 11 +- .../agentic-merge-reference-impl.prompt.md | 17 +- .../prompts/agentic-merge-upstream.prompt.md | 439 ------ .../coding-agent-merge-instructions.md | 19 - .github/scripts/release/update-changelog.sh | 33 +- .../upstream-sync/merge-upstream-diff.sh | 86 -- .../upstream-sync/merge-upstream-finish.sh | 63 - .../upstream-sync/merge-upstream-start.sh | 88 -- .../skills/agentic-merge-upstream/SKILL.md | 7 - .github/workflows/publish-maven.yml | 15 +- .../workflows/weekly-upstream-sync.lock.yml | 1239 ----------------- .github/workflows/weekly-upstream-sync.md | 117 -- .github/workflows/weekly-upstream-sync.yml | 181 --- CHANGELOG.md | 111 +- CONTRIBUTING.md | 3 +- README.md | 3 +- docs/WORKFLOWS.md | 5 +- ...adr-001-semver-pre-general-availability.md | 3 +- ...n-and-reference-implementation-tracking.md | 3 +- .../com/github/copilot/sdk/CommandsTest.java | 3 +- .../github/copilot/sdk/ElicitationTest.java | 3 +- .../com/github/copilot/sdk/HooksTest.java | 4 +- 23 files changed, 113 insertions(+), 2347 deletions(-) delete mode 100644 .claude/skills/agentic-merge-upstream/SKILL.md delete mode 100644 .github/prompts/agentic-merge-upstream.prompt.md delete mode 100644 .github/prompts/coding-agent-merge-instructions.md delete mode 100755 .github/scripts/upstream-sync/merge-upstream-diff.sh delete mode 100755 .github/scripts/upstream-sync/merge-upstream-finish.sh delete mode 100755 .github/scripts/upstream-sync/merge-upstream-start.sh delete mode 100644 .github/skills/agentic-merge-upstream/SKILL.md delete mode 100644 .github/workflows/weekly-upstream-sync.lock.yml delete mode 100644 .github/workflows/weekly-upstream-sync.md delete mode 100644 .github/workflows/weekly-upstream-sync.yml diff --git a/.claude/skills/agentic-merge-upstream/SKILL.md b/.claude/skills/agentic-merge-upstream/SKILL.md deleted file mode 100644 index 32428db89..000000000 --- a/.claude/skills/agentic-merge-upstream/SKILL.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -name: agentic-merge-upstream -description: Merge upstream changes from the official Copilot SDK into this Java SDK. -license: MIT ---- - -Follow instructions in the [agentic-merge-upstream prompt](../../../.github/prompts/agentic-merge-upstream.prompt.md) to merge upstream changes from the official Copilot SDK into this Java SDK. \ No newline at end of file diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index edd40797b..c1a2d8dec 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -9,7 +9,7 @@ These instructions guide GitHub Copilot when assisting with this repository. The - **Tech Stack**: Java 17+, Maven, Jackson for JSON, JUnit for testing - **Purpose**: Provide a Java SDK for programmatic control of GitHub Copilot CLI - **Architecture**: JSON-RPC client communicating with Copilot CLI over stdio -- **Key Goals**: Maintain parity with upstream .NET SDK while following Java idioms +- **Key Goals**: Maintain parity with reference implementation .NET SDK while following Java idioms ## Build & Test Commands @@ -85,7 +85,7 @@ Tests use the official copilot-sdk test harness from `https://github.com/github/ - **E2ETestContext** - Manages test environment with CapiProxy for deterministic API responses - **CapiProxy** - Node.js-based replaying proxy using YAML snapshots from `test/snapshots/` -- Test snapshots are stored in the upstream repo's `test/snapshots/` directory +- Test snapshots are stored in the reference implementation repo's `test/snapshots/` directory ## Key Conventions @@ -217,7 +217,7 @@ Test method names are converted to lowercase snake_case for snapshot filenames t - **DO NOT** modify `target/` directory - this contains build artifacts - **DO NOT** edit `pom.xml` dependencies without careful consideration - this SDK has minimal dependencies by design - **DO NOT** change the Jackson version without testing against all serialization patterns -- **DO NOT** modify test snapshots in `target/copilot-sdk/test/snapshots/` - these come from upstream +- **DO NOT** modify test snapshots in `target/copilot-sdk/test/snapshots/` - these come from reference implementation - **DO NOT** alter the Eclipse formatter configuration in `pom.xml` without team consensus - **DO NOT** remove or skip Checkstyle or Spotless checks @@ -299,12 +299,12 @@ The release process is automated via the `publish-maven.yml` GitHub Actions work - Converts the `## [Unreleased]` section to `## [version] - date` - Creates a new empty `## [Unreleased]` section at the top - Updates version comparison links at the bottom of CHANGELOG.md - - Injects the upstream SDK commit hash (from `.lastmerge`) as a `> **Upstream sync:**` blockquote in both the new `[Unreleased]` section and the released version section + - Injects the reference implementation SDK commit hash (from `.lastmerge`) as a `> **Reference implementation sync:**` blockquote in both the new `[Unreleased]` section and the released version section 2. **Reference Implementation Sync Tracking**: Each release records which commit from the official `github/copilot-sdk` it is synced to: - The `.lastmerge` file is read during the release workflow - The commit hash is injected into `CHANGELOG.md` under the release heading - - Format: `> **Upstream sync:** [\`github/copilot-sdk@SHORT_HASH\`](link-to-commit)` + - Format: `> **Reference implementation sync:** [\`github/copilot-sdk@SHORT_HASH\`](link-to-commit)` 3. **Documentation Updates**: README.md and jbang-example.java are updated with the new version. @@ -316,3 +316,4 @@ The release process is automated via the `publish-maven.yml` GitHub Actions work 5. **Rollback**: If the release fails, the documentation commit is automatically reverted The workflow is triggered manually via workflow_dispatch with optional version parameters. + diff --git a/.github/prompts/agentic-merge-reference-impl.prompt.md b/.github/prompts/agentic-merge-reference-impl.prompt.md index fd7c3fa13..1c19b6f1c 100644 --- a/.github/prompts/agentic-merge-reference-impl.prompt.md +++ b/.github/prompts/agentic-merge-reference-impl.prompt.md @@ -56,7 +56,7 @@ This writes a `.merge-env` file used by the other scripts. It outputs: - The reference-impl dir path - A short log of reference implementation commits since `.lastmerge` -## Step 2: Analyze Upstream Changes +## Step 2: Analyze reference implementation Changes Run the diff script for a detailed breakdown by area: @@ -96,7 +96,7 @@ For each change in the reference implementation diff, determine: ### Key Files to Compare -| Upstream (.NET) | Java SDK Equivalent | +| reference implementation (.NET) | Java SDK Equivalent | |------------------------------------|--------------------------------------------------------| | `dotnet/src/Client.cs` | `src/main/java/com/github/copilot/sdk/CopilotClient.java` | | `dotnet/src/Session.cs` | `src/main/java/com/github/copilot/sdk/CopilotSession.java` | @@ -121,7 +121,7 @@ Before modifying any code: 2. **Identify the Java equivalent approach** - Don't replicate C# patterns; find the idiomatic Java way 3. **Check for existing abstractions** - The Java SDK may already have mechanisms that differ from .NET 4. **Preserve backward compatibility** - Existing API signatures should not break unless absolutely necessary -5. **When in doubt, match existing code** - Follow what's already in the Java SDK, not the upstream +5. **When in doubt, match existing code** - Follow what's already in the Java SDK, not the reference implementation ### Commit Changes Incrementally @@ -181,8 +181,8 @@ After porting implementation changes, **always check for new or updated tests** ```bash cd "$TEMP_DIR/copilot-sdk" -git diff "$LAST_MERGE_COMMIT"..origin/main --stat -- dotnet/test/ -git diff "$LAST_MERGE_COMMIT"..origin/main --stat -- test/snapshots/ +git diff "$LAST_REFERENCE_IMPL_COMMIT"..origin/main --stat -- dotnet/test/ +git diff "$LAST_REFERENCE_IMPL_COMMIT"..origin/main --stat -- test/snapshots/ ``` ### Port Test Cases @@ -196,7 +196,7 @@ For each new or modified test file in `dotnet/test/`: ### Test File Mapping -| Upstream Test (.NET) | Java SDK Test | +| reference implementation Test (.NET) | Java SDK Test | |-----------------------------|--------------------------------------------------------| | `dotnet/test/AskUserTests.cs` | `src/test/java/com/github/copilot/sdk/AskUserTest.java` | | `dotnet/test/HooksTests.cs` | `src/test/java/com/github/copilot/sdk/HooksTest.java` | @@ -209,7 +209,7 @@ New test snapshots are stored in `test/snapshots/` in the reference implementati If tests fail with errors like `TypeError: Cannot read properties of undefined`, the test harness may not yet support the new RPC methods. In this case: -1. **Mark tests as `@Disabled`** with a clear reason (e.g., `@Disabled("Requires test harness update with X support - see upstream PR #NNN")`) +1. **Mark tests as `@Disabled`** with a clear reason (e.g., `@Disabled("Requires test harness update with X support - see reference implementation PR #NNN")`) 2. **Document the dependency** in the test class Javadoc 3. **Enable tests later** once the harness is updated @@ -403,7 +403,7 @@ Before finishing: - [ ] New branch created from `main` - [ ] Copilot CLI updated to latest version - [ ] README.md updated with minimum CLI version requirement -- [ ] Upstream repository cloned +- [ ] reference implementation repository cloned - [ ] Diff analyzed between `.lastmerge` commit and HEAD - [ ] New features/fixes identified - [ ] Changes ported to Java SDK following conventions @@ -437,3 +437,4 @@ Before finishing: - Uses JUnit 5 for testing - **Java SDK design decisions take precedence over reference implementation patterns** - **Adapt reference implementation changes to fit Java idioms, not the other way around** + diff --git a/.github/prompts/agentic-merge-upstream.prompt.md b/.github/prompts/agentic-merge-upstream.prompt.md deleted file mode 100644 index c1d2c54a0..000000000 --- a/.github/prompts/agentic-merge-upstream.prompt.md +++ /dev/null @@ -1,439 +0,0 @@ -# Merge Upstream SDK Changes - -You are an expert Java developer tasked with porting changes from the official Copilot SDK (primarily the .NET implementation) to this Java SDK. - -## ⚠️ IMPORTANT: Java SDK Design Takes Priority - -**The current design and architecture of the Java SDK is the priority.** When porting changes from upstream: - -1. **Adapt, don't copy** - Translate upstream features to fit the Java SDK's existing patterns, naming conventions, and architecture -2. **Preserve Java idioms** - The Java SDK should feel natural to Java developers, not like a C# port -3. **Maintain consistency** - New code must match the existing codebase style and structure -4. **Evaluate before porting** - Not every upstream change needs to be ported; some may not be applicable or may conflict with Java SDK design decisions - -Before making any changes, **read and understand the existing Java SDK implementation** to ensure new code integrates seamlessly. - -## Utility Scripts - -The `.github/scripts/` directory contains helper scripts that automate the repeatable parts of this workflow. **Use these scripts instead of running the commands manually.** - -| Script | Purpose | -|---|---| -| `.github/scripts/upstream-sync/merge-upstream-start.sh` | Creates branch, updates CLI, clones upstream, reads `.lastmerge`, prints commit summary | -| `.github/scripts/upstream-sync/merge-upstream-diff.sh` | Detailed diff analysis grouped by area (`.NET src`, tests, snapshots, docs, etc.) | -| `.github/scripts/upstream-sync/merge-upstream-finish.sh` | Runs format + test + build, updates `.lastmerge`, commits, pushes branch | -| `.github/scripts/build/format-and-test.sh` | Standalone `spotless:apply` + `mvn clean verify` (useful during porting too) | - -All scripts write/read a `.merge-env` file (git-ignored) to share state (branch name, upstream dir, last-merge commit). - -## Workflow Overview - -1. Run `./.github/scripts/upstream-sync/merge-upstream-start.sh` (creates branch, clones upstream, shows summary) -2. Run `./.github/scripts/upstream-sync/merge-upstream-diff.sh` (analyze changes) -3. Update README with minimum CLI version requirement -4. Identify upstream changes to port -5. Apply changes to Java SDK (commit as you go) -6. Port/adjust tests from upstream changes -7. Run `./.github/scripts/build/format-and-test.sh` frequently while porting -8. Build the package -9. Update documentation (**required for every user-facing upstream change**) -10. Run `./.github/scripts/upstream-sync/merge-upstream-finish.sh` (final test + push) and finalize Pull Request (see note below about coding agent vs. manual workflow) -11. Perform final review before handing off - ---- - -## Step 1: Initialize Upstream Sync - -Run the start script to create a branch, update the CLI, clone the upstream repo, and see a summary of new commits: - -```bash -./.github/scripts/upstream-sync/merge-upstream-start.sh -``` - -This writes a `.merge-env` file used by the other scripts. It outputs: -- The branch name created -- The Copilot CLI version -- The upstream dir path -- A short log of upstream commits since `.lastmerge` - -## Step 2: Analyze Upstream Changes - -Run the diff script for a detailed breakdown by area: - -```bash -./.github/scripts/upstream-sync/merge-upstream-diff.sh # stat only -./.github/scripts/upstream-sync/merge-upstream-diff.sh --full # full diffs -``` - -The diff script groups changes into: .NET source, .NET tests, test snapshots, documentation, protocol/config, Go/Node.js/Python SDKs, and other files. - -## Step 3: Update README with CLI Version - -After the start script runs, check the CLI version it printed (also saved in `.merge-env` as `CLI_VERSION`). Update the Requirements section in `README.md` and `src/site/markdown/index.md` to specify the minimum CLI version requirement. - -Commit this change before proceeding: - -```bash -git add README.md src/site/markdown/index.md -git commit -m "Update Copilot CLI minimum version requirement" -``` - -## Step 4: Identify Changes to Port - -Using the output from `merge-upstream-diff.sh`, focus on: -- `dotnet/src/` - Primary reference implementation -- `dotnet/test/` - Test cases to port -- `docs/` - Documentation updates -- `sdk-protocol-version.json` - Protocol version changes - -For each change in the upstream diff, determine: - -1. **New Features**: New methods, classes, or capabilities added to the SDK -2. **Bug Fixes**: Corrections to existing functionality -3. **API Changes**: Changes to public interfaces or method signatures -4. **Protocol Updates**: Changes to the JSON-RPC protocol or message types -5. **Test Updates**: New or modified test cases - -### Key Files to Compare - -| Upstream (.NET) | Java SDK Equivalent | -|------------------------------------|--------------------------------------------------------| -| `dotnet/src/Client.cs` | `src/main/java/com/github/copilot/sdk/CopilotClient.java` | -| `dotnet/src/Session.cs` | `src/main/java/com/github/copilot/sdk/CopilotSession.java` | -| `dotnet/src/Types.cs` | `src/main/java/com/github/copilot/sdk/types/*.java` | -| `dotnet/src/Generated/*.cs` | `src/main/java/com/github/copilot/sdk/types/*.java` | -| `dotnet/test/*.cs` | `src/test/java/com/github/copilot/sdk/*Test.java` | -| `docs/getting-started.md` | `README.md` and `src/site/markdown/*.md` | -| `docs/*.md` (new files) | `src/site/markdown/*.md` + update `src/site/site.xml` | -| `sdk-protocol-version.json` | (embedded in Java code or resource file) | - -> **⚠️ Important:** When adding new documentation pages, always update `src/site/site.xml` to include them in the navigation menu. - -## Step 5: Apply Changes to Java SDK - -When porting changes: - -### ⚠️ Priority: Preserve Java SDK Design - -Before modifying any code: - -1. **Read the existing Java implementation first** - Understand current patterns, class structure, and naming -2. **Identify the Java equivalent approach** - Don't replicate C# patterns; find the idiomatic Java way -3. **Check for existing abstractions** - The Java SDK may already have mechanisms that differ from .NET -4. **Preserve backward compatibility** - Existing API signatures should not break unless absolutely necessary -5. **When in doubt, match existing code** - Follow what's already in the Java SDK, not the upstream - -### Commit Changes Incrementally - -**Important:** Commit your changes as you work, grouping related changes together: - -```bash -# After porting a feature or fix, commit with a descriptive message -git add -git commit -m "Port from upstream" - -# Example commits: -# git commit -m "Port new authentication flow from upstream" -# git commit -m "Add new message types from upstream protocol update" -# git commit -m "Port bug fix for session handling from upstream" -``` - -This creates a clear history of changes that can be reviewed in the Pull Request. - -### General Guidelines - -- **Naming Conventions**: Convert C# PascalCase to Java camelCase for methods/variables -- **Async Patterns**: C# `async/await` → Java `CompletableFuture` or synchronous equivalents -- **Nullable Types**: C# `?` nullable → Java `@Nullable` annotations or `Optional` -- **Properties**: C# properties → Java getters/setters or records -- **Records**: C# records → Java records (Java 17+) -- **Events**: C# events → Java callbacks or listeners - -### Type Mappings - -| C# Type | Java Equivalent | -|------------------------|------------------------------| -| `string` | `String` | -| `int` | `int` / `Integer` | -| `bool` | `boolean` / `Boolean` | -| `Task` | `CompletableFuture` | -| `CancellationToken` | (custom implementation) | -| `IAsyncEnumerable` | `Stream` or `Iterator` | -| `JsonElement` | `JsonNode` (Jackson) | -| `Dictionary` | `Map` | -| `List` | `List` | - -### Code Style - -Follow the existing Java SDK patterns: -- Use Jackson for JSON serialization (`ObjectMapper`) -- Use Java records for DTOs where appropriate -- Follow the existing package structure under `com.github.copilot.sdk` -- Maintain backward compatibility when possible -- **Match the style of surrounding code** - Consistency with existing code is more important than upstream patterns -- **Prefer existing abstractions** - If the Java SDK already solves a problem differently than .NET, keep the Java approach - -## Step 6: Port Tests - -After porting implementation changes, **always check for new or updated tests** in the upstream repository: - -### Check for New Tests - -```bash -cd "$TEMP_DIR/copilot-sdk" -git diff "$LAST_MERGE_COMMIT"..origin/main --stat -- dotnet/test/ -git diff "$LAST_MERGE_COMMIT"..origin/main --stat -- test/snapshots/ -``` - -### Port Test Cases - -For each new or modified test file in `dotnet/test/`: - -1. **Create corresponding Java test class** in `src/test/java/com/github/copilot/sdk/` -2. **Follow existing test patterns** - Look at existing tests like `PermissionsTest.java` for structure -3. **Use the E2ETestContext** infrastructure for tests that need the test harness -4. **Match snapshot directory names** - Test snapshots in `test/snapshots/` must match the directory name used in `ctx.configureForTest()` - -### Test File Mapping - -| Upstream Test (.NET) | Java SDK Test | -|-----------------------------|--------------------------------------------------------| -| `dotnet/test/AskUserTests.cs` | `src/test/java/com/github/copilot/sdk/AskUserTest.java` | -| `dotnet/test/HooksTests.cs` | `src/test/java/com/github/copilot/sdk/HooksTest.java` | -| `dotnet/test/ClientTests.cs` | `src/test/java/com/github/copilot/sdk/CopilotClientTest.java` | -| `dotnet/test/*Tests.cs` | `src/test/java/com/github/copilot/sdk/*Test.java` | - -### Test Snapshot Compatibility - -New test snapshots are stored in `test/snapshots/` in the upstream repository. These snapshots are automatically cloned during the Maven build process. - -If tests fail with errors like `TypeError: Cannot read properties of undefined`, the test harness may not yet support the new RPC methods. In this case: - -1. **Mark tests as `@Disabled`** with a clear reason (e.g., `@Disabled("Requires test harness update with X support - see upstream PR #NNN")`) -2. **Document the dependency** in the test class Javadoc -3. **Enable tests later** once the harness is updated - -### Unit Tests vs E2E Tests - -- **Unit tests** (like auth option validation) can run without the test harness -- **E2E tests** require the test harness with matching snapshots - -Commit tests separately or together with their corresponding implementation changes. - -## Step 7: Format and Run Tests - -After applying changes, use the convenience script: - -```bash -./.github/scripts/build/format-and-test.sh # format + full verify -./.github/scripts/build/format-and-test.sh --debug # with debug logging -``` - -Or for quicker iteration during porting: - -```bash -./.github/scripts/build/format-and-test.sh --format-only # just spotless -./.github/scripts/build/format-and-test.sh --test-only # skip formatting -``` - -### If Tests Fail - -1. Read the test output carefully -2. Identify the root cause (compilation error, runtime error, assertion failure) -3. Fix the issue in the Java code -4. Re-run tests -5. Repeat until all tests pass - -### Common Issues - -- **Missing imports**: Add required import statements -- **Type mismatches**: Ensure proper type conversions -- **Null handling**: Add null checks where C# had nullable types -- **JSON serialization**: Verify Jackson annotations are correct - -## Step 8: Build the Package - -Once tests pass, build the complete package: - -```bash -mvn clean package -DskipTests -``` - -Verify: -- No compilation errors -- No warnings (if possible) -- JAR file is generated in `target/` - -## Step 9: Update Documentation - -**Documentation is critical for new features.** Every new feature ported from upstream must be documented before the merge is complete. -Review and complete this documentation checklist before proceeding to Step 10. -If you determine no docs changes are needed, document that decision and rationale in the PR body under a clear heading (for example, `Documentation Impact`). - -### Documentation Checklist - -For each new feature or significant change: - -1. **README.md**: Update the main README if there are user-facing changes -2. **src/site/markdown/index.md**: Update if requirements or quick start examples change -3. **src/site/markdown/documentation.md**: Add sections for new basic usage patterns -4. **src/site/markdown/advanced.md**: Add sections for new advanced features (tools, handlers, configurations) -5. **src/site/markdown/mcp.md**: Update if MCP-related changes are made -6. **Javadoc**: Add/update Javadoc comments for all new/changed public APIs -7. **src/site/site.xml**: Update if new documentation pages were added - -### Documentation Requirements for New Features - -When adding a new feature, ensure the documentation includes: - -- **What it does**: Clear explanation of the feature's purpose -- **How to use it**: Code example showing typical usage -- **API reference**: Link to relevant Javadoc -- **Configuration options**: All available settings/properties - -### Example: Documenting a New Handler - -If a new handler (like `UserInputHandler`, `PermissionHandler`) is added, create a section in `advanced.md`: - -```markdown -## Feature Name - -Brief description of what the feature does. - -\`\`\`java -var session = client.createSession( - new SessionConfig() - .setOnFeatureRequest((request, invocation) -> { - // Handle the request - return CompletableFuture.completedFuture(result); - }) -).get(); -\`\`\` - -Explain the request/response objects and their properties. - -See [FeatureHandler](apidocs/com/github/copilot/sdk/json/FeatureHandler.html) Javadoc for more details. -``` - -### Verify Documentation Consistency - -Ensure consistency across all documentation files: - -- Requirements section should match in `README.md` and `src/site/markdown/index.md` -- Code examples should use the same patterns and be tested -- Links to Javadoc should use correct paths (`apidocs/...`) - -## Step 10: Finish, Push, and Finalize Pull Request - -Run the finish script which updates `.lastmerge`, runs a final build, and pushes the branch: - -```bash -./.github/scripts/upstream-sync/merge-upstream-finish.sh # full format + test + push -./.github/scripts/upstream-sync/merge-upstream-finish.sh --skip-tests # if tests already passed -``` - -### PR Handling: Coding Agent vs. Manual Workflow - -**If running as a Copilot coding agent** (triggered via GitHub issue assignment by the weekly sync workflow), a pull request has **already been created automatically** for you. Do NOT create a new one. Just push your commits to the current branch — the existing PR will be updated. Add the `upstream-sync` label to the existing PR by running this command in a terminal: - -```bash -gh pr edit --add-label "upstream-sync" -``` - -> **No-changes scenario (coding agent only):** If after analyzing the upstream diff there are no relevant changes to port to the Java SDK, push an empty commit with a message explaining why no changes were needed, so the PR reflects the analysis outcome. The repository maintainer will close the PR and issue manually. - -**If running manually** (e.g., from VS Code via the reusable prompt), create the Pull Request using `gh` CLI or the GitHub MCP tool. Then add the label: - -```bash -gh pr create --base main --title "Merge upstream SDK changes (YYYY-MM-DD)" --body-file /dev/stdin <<< "$PR_BODY" -gh pr edit --add-label "upstream-sync" -``` - -The PR body should include: -1. **Title**: `Merge upstream SDK changes (YYYY-MM-DD)` -2. **Body** with: - - Summary of upstream commits analyzed (with count and commit range) - - Table of changes ported (commit hash + description) - - List of changes intentionally not ported (with reasons) - - Verification status (test count, build status) - -### PR Body Template - -```markdown -## Upstream Merge - -Ports changes from the official Copilot SDK ([github/copilot-sdk](https://github.com/github/copilot-sdk)) since last merge (``→``). - -### Upstream commits analyzed (N commits) - -- Brief description of each upstream change and whether it was ported or not - -### Changes ported - -| Commit | Description | -|---|---| -| `` | Description of change | - -### Not ported (intentionally) - -- **Feature name** — Reason why it wasn't ported - -### Verification - -- All **N tests pass** (`mvn clean test`) -- Package builds successfully (`mvn clean package -DskipTests`) -- Code formatted with Spotless -``` - -## Step 11: Final Review - -Before finishing: - -1. Run `git log --oneline main..$BRANCH_NAME` to review all commits -2. Run `git diff main..$BRANCH_NAME --stat` to see a summary of all changes -3. Ensure no unintended changes were made -4. Verify code follows project conventions -5. Confirm the branch was pushed to remote -6. Confirm the Pull Request is ready (created or updated) and provide the PR URL to the user - ---- - -## Checklist - -- [ ] New branch created from `main` -- [ ] Copilot CLI updated to latest version -- [ ] README.md updated with minimum CLI version requirement -- [ ] Upstream repository cloned -- [ ] Diff analyzed between `.lastmerge` commit and HEAD -- [ ] New features/fixes identified -- [ ] Changes ported to Java SDK following conventions -- [ ] **New/updated tests ported from upstream** (check `dotnet/test/` and `test/snapshots/`) -- [ ] Tests marked `@Disabled` if harness doesn't support new features yet -- [ ] Changes committed incrementally with descriptive messages -- [ ] `mvn test` passes -- [ ] `mvn package` builds successfully -- [ ] **Documentation updated for new features:** - - [ ] `README.md` updated if user-facing changes - - [ ] `src/site/markdown/index.md` updated if requirements changed - - [ ] `src/site/markdown/documentation.md` updated for new basic usage - - [ ] `src/site/markdown/advanced.md` updated for new advanced features - - [ ] Javadoc added/updated for new public APIs -- [ ] If no documentation files were changed for user-facing upstream changes, PR body explicitly explains why documentation changes were not needed -- [ ] `src/site/site.xml` updated if new documentation pages were added -- [ ] `.lastmerge` file updated with new commit hash -- [ ] Branch pushed to remote -- [ ] **Pull Request finalized** (coding agent: push to existing PR; manual: create via `mcp_github_create_pull_request`) -- [ ] **`upstream-sync` label added** to the PR via `mcp_github_add_issue_labels` -- [ ] PR URL provided to user - ---- - -## Notes - -- The upstream SDK is at: `https://github.com/github/copilot-sdk.git` -- Primary reference implementation is in `dotnet/` folder -- This Java SDK targets Java 17+ -- Uses Jackson for JSON processing -- Uses JUnit 5 for testing -- **Java SDK design decisions take precedence over upstream patterns** -- **Adapt upstream changes to fit Java idioms, not the other way around** diff --git a/.github/prompts/coding-agent-merge-instructions.md b/.github/prompts/coding-agent-merge-instructions.md deleted file mode 100644 index 1c18e1f5f..000000000 --- a/.github/prompts/coding-agent-merge-instructions.md +++ /dev/null @@ -1,19 +0,0 @@ - - - -Follow the agentic-merge-upstream prompt at .github/prompts/agentic-merge-upstream.prompt.md -to port upstream changes to the Java SDK. - -Use the utility scripts in .github/scripts/ subfolders for initialization, diffing, formatting, and testing. -Commit changes incrementally. Update .lastmerge when done. - -IMPORTANT: A pull request has already been created automatically for you — do NOT create a new -one. Push your commits to the current branch, and the existing PR will be updated. - -Add the 'upstream-sync' label to the existing PR by running this command in a terminal: - - gh pr edit --add-label "upstream-sync" - -If after analyzing the upstream diff there are no relevant changes to port to the Java SDK, -push an empty commit with a message explaining why no changes were needed, so the PR reflects -the analysis outcome. The repository maintainer will close the PR and issue manually. diff --git a/.github/scripts/release/update-changelog.sh b/.github/scripts/release/update-changelog.sh index a18d35b02..926da5b3b 100755 --- a/.github/scripts/release/update-changelog.sh +++ b/.github/scripts/release/update-changelog.sh @@ -2,24 +2,24 @@ set -e # Script to update CHANGELOG.md during release process -# Usage: ./update-changelog.sh [upstream-hash] +# Usage: ./update-changelog.sh [reference implementation-hash] # Example: ./update-changelog.sh 1.0.8 # Example: ./update-changelog.sh 1.0.8 05e3c46c8c23130c9c064dc43d00ec78f7a75eab if [ -z "$1" ]; then echo "Error: Version argument required" - echo "Usage: $0 [upstream-hash]" + echo "Usage: $0 [reference implementation-hash]" exit 1 fi VERSION="$1" -UPSTREAM_HASH="${2:-}" +REFERENCE_IMPL_HASH="${2:-}" CHANGELOG_FILE="${CHANGELOG_FILE:-CHANGELOG.md}" RELEASE_DATE=$(date +%Y-%m-%d) echo "Updating CHANGELOG.md for version ${VERSION} (${RELEASE_DATE})" -if [ -n "$UPSTREAM_HASH" ]; then - echo " Upstream SDK sync: ${UPSTREAM_HASH:0:7}" +if [ -n "$REFERENCE_IMPL_HASH" ]; then + echo " Reference implementation SDK sync: ${REFERENCE_IMPL_HASH:0:7}" fi # Check if CHANGELOG.md exists @@ -38,7 +38,7 @@ fi TEMP_FILE=$(mktemp) # Process the CHANGELOG -awk -v version="$VERSION" -v date="$RELEASE_DATE" -v upstream_hash="$UPSTREAM_HASH" ' +awk -v version="$VERSION" -v date="$RELEASE_DATE" -v REFERENCE_IMPL_HASH="$REFERENCE_IMPL_HASH" ' BEGIN { unreleased_found = 0 content_found = 0 @@ -65,26 +65,26 @@ links_section && repo_url == "" && /^\[[0-9]+\.[0-9]+\.[0-9]+(-java\.[0-9]+)?\]: if (!unreleased_found) { print "## [Unreleased]" print "" - if (upstream_hash != "") { - short_hash = substr(upstream_hash, 1, 7) - print "> **Upstream sync:** [`github/copilot-sdk@" short_hash "`](https://github.com/github/copilot-sdk/commit/" upstream_hash ")" + if (REFERENCE_IMPL_HASH != "") { + short_hash = substr(REFERENCE_IMPL_HASH, 1, 7) + print "> **Reference implementation sync:** [`github/copilot-sdk@" short_hash "`](https://github.com/github/copilot-sdk/commit/" REFERENCE_IMPL_HASH ")" print "" } print "## [" version "] - " date - if (upstream_hash != "") { + if (REFERENCE_IMPL_HASH != "") { print "" - print "> **Upstream sync:** [`github/copilot-sdk@" short_hash "`](https://github.com/github/copilot-sdk/commit/" upstream_hash ")" + print "> **Reference implementation sync:** [`github/copilot-sdk@" short_hash "`](https://github.com/github/copilot-sdk/commit/" REFERENCE_IMPL_HASH ")" } unreleased_found = 1 - skip_old_upstream = 1 + skip_old_reference_impl = 1 next } } -# Skip the old upstream sync line and surrounding blank lines from the previous [Unreleased] section -skip_old_upstream && /^[[:space:]]*$/ { next } -skip_old_upstream && /^> \*\*Upstream sync:\*\*/ { next } -skip_old_upstream && !/^[[:space:]]*$/ && !/^> \*\*Upstream sync:\*\*/ { skip_old_upstream = 0 } +# Skip the old Reference implementation sync line and surrounding blank lines from the previous [Unreleased] section +skip_old_reference_impl && /^[[:space:]]*$/ { next } +skip_old_reference_impl && /^> \*\*Reference implementation sync:\*\*/ { next } +skip_old_reference_impl && !/^[[:space:]]*$/ && !/^> \*\*Reference implementation sync:\*\*/ { skip_old_reference_impl = 0 } # Capture the first version link to get the previous version links_section && first_version_link == "" && /^\[[0-9]+\.[0-9]+\.[0-9]+(-java\.[0-9]+)?\]:/ { @@ -119,3 +119,4 @@ echo "✓ CHANGELOG.md updated successfully" echo " - Added version ${VERSION} with date ${RELEASE_DATE}" echo " - Created new [Unreleased] section" echo " - Updated version comparison links" + diff --git a/.github/scripts/upstream-sync/merge-upstream-diff.sh b/.github/scripts/upstream-sync/merge-upstream-diff.sh deleted file mode 100755 index ee61b6ffc..000000000 --- a/.github/scripts/upstream-sync/merge-upstream-diff.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env bash -# ────────────────────────────────────────────────────────────── -# merge-upstream-diff.sh -# -# Generates a detailed diff analysis of upstream changes since -# the last merge, grouped by area of interest: -# • .NET source (primary reference) -# • .NET tests -# • Test snapshots -# • Documentation -# • Protocol / config files -# -# Usage: ./.github/scripts/upstream-sync/merge-upstream-diff.sh [--full] -# --full Show actual diffs, not just stats -# -# Requires: .merge-env written by merge-upstream-start.sh -# ────────────────────────────────────────────────────────────── -set -euo pipefail - -ROOT_DIR="$(cd "$(dirname "$0")/../../.." && pwd)" -ENV_FILE="$ROOT_DIR/.merge-env" - -if [[ ! -f "$ENV_FILE" ]]; then - echo "❌ $ENV_FILE not found. Run ./.github/scripts/upstream-sync/merge-upstream-start.sh first." - exit 1 -fi - -# shellcheck source=/dev/null -source "$ENV_FILE" - -SHOW_FULL=false -if [[ "${1:-}" == "--full" ]]; then - SHOW_FULL=true -fi - -cd "$UPSTREAM_DIR" -git fetch origin main 2>/dev/null - -RANGE="$LAST_MERGE_COMMIT..origin/main" - -echo "════════════════════════════════════════════════════════════" -echo " Upstream diff analysis: $RANGE" -echo "════════════════════════════════════════════════════════════" - -# ── Commit log ──────────────────────────────────────────────── -echo "" -echo "── Commit log ──" -git log --oneline --no-decorate "$RANGE" -echo "" - -# Helper to print a section -section() { - local title="$1"; shift - local paths=("$@") - - echo "── $title ──" - local stat - stat=$(git diff "$RANGE" --stat -- "${paths[@]}" 2>/dev/null || true) - if [[ -z "$stat" ]]; then - echo " (no changes)" - else - echo "$stat" - if $SHOW_FULL; then - echo "" - git diff "$RANGE" -- "${paths[@]}" 2>/dev/null || true - fi - fi - echo "" -} - -# ── Sections ────────────────────────────────────────────────── -section ".NET source (dotnet/src)" "dotnet/src/" -section ".NET tests (dotnet/test)" "dotnet/test/" -section "Test snapshots" "test/snapshots/" -section "Documentation (docs/)" "docs/" -section "Protocol & config" "sdk-protocol-version.json" "package.json" "justfile" -section "Go SDK" "go/" -section "Node.js SDK" "nodejs/" -section "Python SDK" "python/" -section "Other files" "README.md" "CONTRIBUTING.md" "SECURITY.md" "SUPPORT.md" - -echo "════════════════════════════════════════════════════════════" -echo " To see full diffs: $0 --full" -echo " To see a specific path:" -echo " cd $UPSTREAM_DIR && git diff $RANGE -- " -echo "════════════════════════════════════════════════════════════" diff --git a/.github/scripts/upstream-sync/merge-upstream-finish.sh b/.github/scripts/upstream-sync/merge-upstream-finish.sh deleted file mode 100755 index 1663ef259..000000000 --- a/.github/scripts/upstream-sync/merge-upstream-finish.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env bash -# ────────────────────────────────────────────────────────────── -# merge-upstream-finish.sh -# -# Finalises an upstream merge: -# 1. Runs format + test + build (via format-and-test.sh) -# 2. Updates .lastmerge to upstream HEAD -# 3. Commits the .lastmerge update -# 4. Pushes the branch to origin -# -# Usage: ./.github/scripts/upstream-sync/merge-upstream-finish.sh -# ./.github/scripts/upstream-sync/merge-upstream-finish.sh --skip-tests -# -# Requires: .merge-env written by merge-upstream-start.sh -# ────────────────────────────────────────────────────────────── -set -euo pipefail - -ROOT_DIR="$(cd "$(dirname "$0")/../../.." && pwd)" -ENV_FILE="$ROOT_DIR/.merge-env" - -if [[ ! -f "$ENV_FILE" ]]; then - echo "❌ $ENV_FILE not found. Run ./.github/scripts/upstream-sync/merge-upstream-start.sh first." - exit 1 -fi - -# shellcheck source=/dev/null -source "$ENV_FILE" - -SKIP_TESTS=false -if [[ "${1:-}" == "--skip-tests" ]]; then - SKIP_TESTS=true -fi - -cd "$ROOT_DIR" - -# ── 1. Format, test, build ─────────────────────────────────── -if $SKIP_TESTS; then - echo "▸ Formatting only (tests skipped)…" - mvn spotless:apply - mvn clean package -DskipTests -else - echo "▸ Running format + test + build…" - "$ROOT_DIR/.github/scripts/build/format-and-test.sh" -fi - -# ── 2. Update .lastmerge ───────────────────────────────────── -echo "▸ Updating .lastmerge…" -NEW_COMMIT=$(cd "$UPSTREAM_DIR" && git rev-parse origin/main) -echo "$NEW_COMMIT" > "$ROOT_DIR/.lastmerge" - -git add .lastmerge -git commit -m "Update .lastmerge to $NEW_COMMIT" - -# ── 3. Push branch ─────────────────────────────────────────── -echo "▸ Pushing branch $BRANCH_NAME to origin…" -git push -u origin "$BRANCH_NAME" - -echo "" -echo "✅ Branch pushed. Next step:" -echo " Create a Pull Request (base: main, head: $BRANCH_NAME)" -echo "" -echo " Suggested title: Merge upstream SDK changes ($(date +%Y-%m-%d))" -echo " Don't forget to add the 'upstream-sync' label." diff --git a/.github/scripts/upstream-sync/merge-upstream-start.sh b/.github/scripts/upstream-sync/merge-upstream-start.sh deleted file mode 100755 index 755361cd1..000000000 --- a/.github/scripts/upstream-sync/merge-upstream-start.sh +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env bash -# ────────────────────────────────────────────────────────────── -# merge-upstream-start.sh -# -# Prepares the workspace for an upstream merge: -# 1. Creates a dated branch from main -# 2. Updates Copilot CLI and records the new version -# 3. Clones the upstream copilot-sdk repo into a temp dir -# 4. Reads .lastmerge and prints a short summary of new commits -# -# Usage: ./.github/scripts/upstream-sync/merge-upstream-start.sh -# Output: Exports UPSTREAM_DIR and LAST_MERGE_COMMIT to a -# .merge-env file so other scripts can source it. -# ────────────────────────────────────────────────────────────── -set -euo pipefail - -ROOT_DIR="$(cd "$(dirname "$0")/../../.." && pwd)" -cd "$ROOT_DIR" - -UPSTREAM_REPO="https://github.com/github/copilot-sdk.git" -ENV_FILE="$ROOT_DIR/.merge-env" - -# ── 1. Create branch (or reuse existing) ───────────────────── -CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) - -if [[ "$CURRENT_BRANCH" != "main" ]]; then - # Already on a non-main branch (e.g., coding agent's auto-created PR branch). - # Stay on this branch — do not create a new one. - BRANCH_NAME="$CURRENT_BRANCH" - echo "▸ Already on branch '$BRANCH_NAME' — reusing it (coding agent mode)." - git pull origin main --no-edit 2>/dev/null || echo " (pull from main skipped or fast-forward not possible)" -else - echo "▸ Ensuring main is up to date…" - git pull origin main - - BRANCH_NAME="merge-upstream-$(date +%Y%m%d)" - echo "▸ Creating branch: $BRANCH_NAME" - git checkout -b "$BRANCH_NAME" -fi - -# ── 2. Update Copilot CLI ──────────────────────────────────── -echo "▸ Updating Copilot CLI…" -if command -v copilot &>/dev/null; then - copilot update || echo " (copilot update returned non-zero – check manually)" - CLI_VERSION=$(copilot --version | head -n 1 | awk '{print $NF}') - echo " Copilot CLI version: $CLI_VERSION" -else - echo " ⚠ 'copilot' command not found – skipping CLI update." - CLI_VERSION="UNKNOWN" -fi - -# ── 3. Clone upstream ──────────────────────────────────────── -TEMP_DIR=$(mktemp -d) -UPSTREAM_DIR="$TEMP_DIR/copilot-sdk" -echo "▸ Cloning upstream into $UPSTREAM_DIR …" -git clone --depth=200 "$UPSTREAM_REPO" "$UPSTREAM_DIR" - -# ── 4. Read last merge commit ──────────────────────────────── -if [[ ! -f "$ROOT_DIR/.lastmerge" ]]; then - echo "❌ .lastmerge file not found in repo root." - exit 1 -fi -LAST_MERGE_COMMIT=$(tr -d '[:space:]' < "$ROOT_DIR/.lastmerge") -echo "▸ Last merged upstream commit: $LAST_MERGE_COMMIT" - -# Quick summary -echo "" -echo "── Upstream commits since last merge ──" -(cd "$UPSTREAM_DIR" && git fetch origin main && \ - git log --oneline "$LAST_MERGE_COMMIT"..origin/main) || \ - echo " (could not generate log – the commit may have been rebased)" -echo "" - -# ── 5. Write env file for other scripts ────────────────────── -cat > "$ENV_FILE" <[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\(-java\.[0-9][0-9]*\)\{0,1\}|${VERSION}|g" README.md @@ -249,3 +249,4 @@ jobs: -f publish_as_latest=true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + diff --git a/.github/workflows/weekly-upstream-sync.lock.yml b/.github/workflows/weekly-upstream-sync.lock.yml deleted file mode 100644 index c2bceee20..000000000 --- a/.github/workflows/weekly-upstream-sync.lock.yml +++ /dev/null @@ -1,1239 +0,0 @@ -# -# ___ _ _ -# / _ \ | | (_) -# | |_| | __ _ ___ _ __ | |_ _ ___ -# | _ |/ _` |/ _ \ '_ \| __| |/ __| -# | | | | (_| | __/ | | | |_| | (__ -# \_| |_/\__, |\___|_| |_|\__|_|\___| -# __/ | -# _ _ |___/ -# | | | | / _| | -# | | | | ___ _ __ _ __| |_| | _____ ____ -# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___| -# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ -# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ -# -# This file was automatically generated by gh-aw (v0.51.6). DO NOT EDIT. -# -# To update this file, edit the corresponding .md file and run: -# gh aw compile -# Not all edits will cause changes to this file. -# -# For more information: https://github.github.com/gh-aw/introduction/overview/ -# -# Weekly upstream sync workflow. Checks for new commits in the official -# Copilot SDK (github/copilot-sdk) and assigns to Copilot to port changes. -# -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"fc14b09206c7aeafcd52c843adce996a1c14cf15875f9b647ef71f631b3b296e","compiler_version":"v0.51.6"} - -name: "Weekly Upstream Sync Agentic Workflow" -"on": - schedule: - - cron: "39 8 * * 2" - # Friendly format: weekly (scattered) - workflow_dispatch: - -permissions: {} - -concurrency: - group: "gh-aw-${{ github.workflow }}" - -run-name: "Weekly Upstream Sync Agentic Workflow" - -jobs: - activation: - runs-on: ubuntu-slim - permissions: - contents: read - outputs: - comment_id: "" - comment_repo: "" - model: ${{ steps.generate_aw_info.outputs.model }} - secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} - steps: - - name: Setup Scripts - uses: github/gh-aw/actions/setup@33cd6c7f1fee588654ef19def2e6a4174be66197 # v0.51.6 - with: - destination: /opt/gh-aw/actions - - name: Generate agentic run info - id: generate_aw_info - env: - GH_AW_INFO_ENGINE_ID: "copilot" - GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" - GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} - GH_AW_INFO_VERSION: "" - GH_AW_INFO_AGENT_VERSION: "0.0.420" - GH_AW_INFO_CLI_VERSION: "v0.51.6" - GH_AW_INFO_WORKFLOW_NAME: "Weekly Upstream Sync Agentic Workflow" - GH_AW_INFO_EXPERIMENTAL: "false" - GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" - GH_AW_INFO_STAGED: "false" - GH_AW_INFO_ALLOWED_DOMAINS: '["defaults","github"]' - GH_AW_INFO_FIREWALL_ENABLED: "true" - GH_AW_INFO_AWF_VERSION: "v0.23.0" - GH_AW_INFO_AWMG_VERSION: "" - GH_AW_INFO_FIREWALL_TYPE: "squid" - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const { main } = require('/opt/gh-aw/actions/generate_aw_info.cjs'); - await main(core, context); - - name: Validate COPILOT_GITHUB_TOKEN secret - id: validate-secret - run: /opt/gh-aw/actions/validate_multi_secret.sh COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default - env: - COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - - name: Checkout .github and .agents folders - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - sparse-checkout: | - .github - .agents - sparse-checkout-cone-mode: true - fetch-depth: 1 - persist-credentials: false - - name: Check workflow file timestamps - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_WORKFLOW_FILE: "weekly-upstream-sync.lock.yml" - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/check_workflow_timestamp_api.cjs'); - await main(); - - name: Create prompt with built-in context - env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} - GH_AW_GITHUB_ACTOR: ${{ github.actor }} - GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} - GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} - GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} - GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} - run: | - bash /opt/gh-aw/actions/create_prompt_first.sh - { - cat << 'GH_AW_PROMPT_EOF' - - GH_AW_PROMPT_EOF - cat "/opt/gh-aw/prompts/xpia.md" - cat "/opt/gh-aw/prompts/temp_folder_prompt.md" - cat "/opt/gh-aw/prompts/markdown.md" - cat "/opt/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_EOF' - - Tools: add_comment, create_issue, close_issue, assign_to_agent, missing_tool, missing_data, noop - - - The following GitHub context information is available for this workflow: - {{#if __GH_AW_GITHUB_ACTOR__ }} - - **actor**: __GH_AW_GITHUB_ACTOR__ - {{/if}} - {{#if __GH_AW_GITHUB_REPOSITORY__ }} - - **repository**: __GH_AW_GITHUB_REPOSITORY__ - {{/if}} - {{#if __GH_AW_GITHUB_WORKSPACE__ }} - - **workspace**: __GH_AW_GITHUB_WORKSPACE__ - {{/if}} - {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }} - - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ - {{/if}} - {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }} - - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ - {{/if}} - {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }} - - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ - {{/if}} - {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }} - - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__ - {{/if}} - {{#if __GH_AW_GITHUB_RUN_ID__ }} - - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__ - {{/if}} - - - GH_AW_PROMPT_EOF - cat << 'GH_AW_PROMPT_EOF' - - GH_AW_PROMPT_EOF - cat << 'GH_AW_PROMPT_EOF' - {{#runtime-import .github/workflows/weekly-upstream-sync.md}} - GH_AW_PROMPT_EOF - } > "$GH_AW_PROMPT" - - name: Interpolate variables and render templates - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/interpolate_prompt.cjs'); - await main(); - - name: Substitute placeholders - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_GITHUB_ACTOR: ${{ github.actor }} - GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} - GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} - GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} - GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - - const substitutePlaceholders = require('/opt/gh-aw/actions/substitute_placeholders.cjs'); - - // Call the substitution function - return await substitutePlaceholders({ - file: process.env.GH_AW_PROMPT, - substitutions: { - GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR, - GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID, - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER, - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER, - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER, - GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY, - GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID, - GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE - } - }); - - name: Validate prompt placeholders - env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - run: bash /opt/gh-aw/actions/validate_prompt_placeholders.sh - - name: Print prompt - env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - run: bash /opt/gh-aw/actions/print_prompt_summary.sh - - name: Upload activation artifact - if: success() - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 - with: - name: activation - path: | - /tmp/gh-aw/aw_info.json - /tmp/gh-aw/aw-prompts/prompt.txt - retention-days: 1 - - agent: - needs: activation - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - issues: read - concurrency: - group: "gh-aw-copilot-${{ github.workflow }}" - env: - DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - GH_AW_ASSETS_ALLOWED_EXTS: "" - GH_AW_ASSETS_BRANCH: "" - GH_AW_ASSETS_MAX_SIZE_KB: 0 - GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs - GH_AW_SAFE_OUTPUTS: /opt/gh-aw/safeoutputs/outputs.jsonl - GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json - GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json - GH_AW_WORKFLOW_ID_SANITIZED: weeklyupstreamsync - outputs: - checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} - detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }} - detection_success: ${{ steps.detection_conclusion.outputs.success }} - has_patch: ${{ steps.collect_output.outputs.has_patch }} - model: ${{ needs.activation.outputs.model }} - output: ${{ steps.collect_output.outputs.output }} - output_types: ${{ steps.collect_output.outputs.output_types }} - steps: - - name: Setup Scripts - uses: github/gh-aw/actions/setup@33cd6c7f1fee588654ef19def2e6a4174be66197 # v0.51.6 - with: - destination: /opt/gh-aw/actions - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - persist-credentials: false - - name: Create gh-aw temp directory - run: bash /opt/gh-aw/actions/create_gh_aw_tmp_dir.sh - - name: Configure Git credentials - env: - REPO_NAME: ${{ github.repository }} - SERVER_URL: ${{ github.server_url }} - run: | - git config --global user.email "github-actions[bot]@users.noreply.github.com" - git config --global user.name "github-actions[bot]" - git config --global am.keepcr true - # Re-authenticate git with GitHub token - SERVER_URL_STRIPPED="${SERVER_URL#https://}" - git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" - echo "Git configured with standard GitHub Actions identity" - - name: Checkout PR branch - id: checkout-pr - if: | - (github.event.pull_request) || (github.event.issue.pull_request) - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - with: - github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/checkout_pr_branch.cjs'); - await main(); - - name: Install GitHub Copilot CLI - run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.420 - - name: Install awf binary - run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.23.0 - - name: Determine automatic lockdown mode for GitHub MCP Server - id: determine-automatic-lockdown - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} - GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} - with: - script: | - const determineAutomaticLockdown = require('/opt/gh-aw/actions/determine_automatic_lockdown.cjs'); - await determineAutomaticLockdown(github, context, core); - - name: Download container images - run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.6 ghcr.io/github/github-mcp-server:v0.31.0 node:lts-alpine - - name: Write Safe Outputs Config - run: | - mkdir -p /opt/gh-aw/safeoutputs - mkdir -p /tmp/gh-aw/safeoutputs - mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF' - {"add_comment":{"max":10,"target":"*"},"assign_to_agent":{"default_agent":"copilot","max":1,"target":"*"},"close_issue":{"max":10,"required_labels":["upstream-sync"],"target":"*"},"create_issue":{"expires":144,"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1}} - GH_AW_SAFE_OUTPUTS_CONFIG_EOF - cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF' - [ - { - "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 1 issue(s) can be created. Title will be prefixed with \"[upstream-sync] \". Labels [upstream-sync] will be automatically added. Assignees [copilot] will be automatically assigned.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "body": { - "description": "Detailed issue description in Markdown. Do NOT repeat the title as a heading since it already appears as the issue's h1. Include context, reproduction steps, or acceptance criteria as appropriate.", - "type": "string" - }, - "labels": { - "description": "Labels to categorize the issue (e.g., 'bug', 'enhancement'). Labels must exist in the repository.", - "items": { - "type": "string" - }, - "type": "array" - }, - "parent": { - "description": "Parent issue number for creating sub-issues. This is the numeric ID from the GitHub URL (e.g., 42 in github.com/owner/repo/issues/42). Can also be a temporary_id (e.g., 'aw_abc123', 'aw_Test123') from a previously created issue in the same workflow run.", - "type": [ - "number", - "string" - ] - }, - "temporary_id": { - "description": "Unique temporary identifier for referencing this issue before it's created. Format: 'aw_' followed by 3 to 8 alphanumeric characters (e.g., 'aw_abc1', 'aw_Test123'). Use '#aw_ID' in body text to reference other issues by their temporary_id; these are replaced with actual issue numbers after creation.", - "pattern": "^aw_[A-Za-z0-9]{3,8}$", - "type": "string" - }, - "title": { - "description": "Concise issue title summarizing the bug, feature, or task. The title appears as the main heading, so keep it brief and descriptive.", - "type": "string" - } - }, - "required": [ - "title", - "body" - ], - "type": "object" - }, - "name": "create_issue" - }, - { - "description": "Close a GitHub issue with a closing comment. You can and should always add a comment when closing an issue to explain the action or provide context. This tool is ONLY for closing issues - use update_issue if you need to change the title, body, labels, or other metadata without closing. Use close_issue when work is complete, the issue is no longer relevant, or it's a duplicate. The closing comment should explain the resolution or reason for closing. If the issue is already closed, a comment will still be posted. CONSTRAINTS: Maximum 10 issue(s) can be closed. Target: *.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "body": { - "description": "Closing comment explaining why the issue is being closed and summarizing any resolution, workaround, or conclusion.", - "type": "string" - }, - "issue_number": { - "description": "Issue number to close. This is the numeric ID from the GitHub URL (e.g., 901 in github.com/owner/repo/issues/901). If omitted, closes the issue that triggered this workflow (requires an issue event trigger).", - "type": [ - "number", - "string" - ] - } - }, - "required": [ - "body" - ], - "type": "object" - }, - "name": "close_issue" - }, - { - "description": "Add a comment to an existing GitHub issue, pull request, or discussion. Use this to provide feedback, answer questions, or add information to an existing conversation. For creating new items, use create_issue, create_discussion, or create_pull_request instead. IMPORTANT: Comments are subject to validation constraints enforced by the MCP server - maximum 65536 characters for the complete comment (including footer which is added automatically), 10 mentions (@username), and 50 links. Exceeding these limits will result in an immediate error with specific guidance. NOTE: By default, this tool requires discussions:write permission. If your GitHub App lacks Discussions permission, set 'discussions: false' in the workflow's safe-outputs.add-comment configuration to exclude this permission. CONSTRAINTS: Maximum 10 comment(s) can be added. Target: *.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "body": { - "description": "The comment text in Markdown format. This is the 'body' field - do not use 'comment_body' or other variations. Provide helpful, relevant information that adds value to the conversation. CONSTRAINTS: The complete comment (your body text + automatically added footer) must not exceed 65536 characters total. Maximum 10 mentions (@username), maximum 50 links (http/https URLs). A footer (~200-500 characters) is automatically appended with workflow attribution, so leave adequate space. If these limits are exceeded, the tool call will fail with a detailed error message indicating which constraint was violated.", - "type": "string" - }, - "item_number": { - "description": "The issue, pull request, or discussion number to comment on. This is the numeric ID from the GitHub URL (e.g., 123 in github.com/owner/repo/issues/123). If omitted, the tool auto-targets the issue, PR, or discussion that triggered this workflow. Auto-targeting only works for issue, pull_request, discussion, and comment event triggers — it does NOT work for schedule, workflow_dispatch, push, or workflow_run triggers. For those trigger types, always provide item_number explicitly, or the comment will be silently discarded.", - "type": "number" - } - }, - "required": [ - "body" - ], - "type": "object" - }, - "name": "add_comment" - }, - { - "description": "Assign the GitHub Copilot coding agent to work on an issue or pull request. The agent will analyze the issue/PR and attempt to implement a solution, creating a pull request when complete. Use this to delegate coding tasks to Copilot. Example usage: assign_to_agent(issue_number=123, agent=\"copilot\") or assign_to_agent(pull_number=456, agent=\"copilot\", pull_request_repo=\"owner/repo\") CONSTRAINTS: Maximum 1 issue(s) can be assigned to agent.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "agent": { - "description": "Agent identifier to assign. Defaults to 'copilot' (the Copilot coding agent) if not specified.", - "type": "string" - }, - "issue_number": { - "description": "Issue number to assign the Copilot coding agent to. This is the numeric ID from the GitHub URL (e.g., 234 in github.com/owner/repo/issues/234). Can also be a temporary_id (e.g., 'aw_abc123', 'aw_Test123') from an issue created earlier in the same workflow run. The issue should contain clear, actionable requirements. Either issue_number or pull_number must be provided, but not both.", - "type": [ - "number", - "string" - ] - }, - "pull_number": { - "description": "Pull request number to assign the Copilot coding agent to. This is the numeric ID from the GitHub URL (e.g., 456 in github.com/owner/repo/pull/456). Either issue_number or pull_number must be provided, but not both.", - "type": [ - "number", - "string" - ] - }, - "pull_request_repo": { - "description": "Target repository where the pull request should be created, in 'owner/repo' format. If omitted, the PR will be created in the same repository as the issue. This allows issues and code to live in different repositories. The global pull-request-repo configuration (if set) is automatically allowed; additional repositories must be listed in allowed-pull-request-repos.", - "type": "string" - } - }, - "type": "object" - }, - "name": "assign_to_agent" - }, - { - "description": "Report that a tool or capability needed to complete the task is not available, or share any information you deem important about missing functionality or limitations. Use this when you cannot accomplish what was requested because the required functionality is missing or access is restricted.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "alternatives": { - "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).", - "type": "string" - }, - "reason": { - "description": "Explanation of why this tool is needed or what information you want to share about the limitation (max 256 characters).", - "type": "string" - }, - "tool": { - "description": "Optional: Name or description of the missing tool or capability (max 128 characters). Be specific about what functionality is needed.", - "type": "string" - } - }, - "required": [ - "reason" - ], - "type": "object" - }, - "name": "missing_tool" - }, - { - "description": "Log a transparency message when no significant actions are needed. Use this to confirm workflow completion and provide visibility when analysis is complete but no changes or outputs are required (e.g., 'No issues found', 'All checks passed'). This ensures the workflow produces human-visible output even when no other actions are taken.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "message": { - "description": "Status or completion message to log. Should explain what was analyzed and the outcome (e.g., 'Code review complete - no issues found', 'Analysis complete - all tests passing').", - "type": "string" - } - }, - "required": [ - "message" - ], - "type": "object" - }, - "name": "noop" - }, - { - "description": "Report that data or information needed to complete the task is not available. Use this when you cannot accomplish what was requested because required data, context, or information is missing.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "alternatives": { - "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).", - "type": "string" - }, - "context": { - "description": "Additional context about the missing data or where it should come from (max 256 characters).", - "type": "string" - }, - "data_type": { - "description": "Type or description of the missing data or information (max 128 characters). Be specific about what data is needed.", - "type": "string" - }, - "reason": { - "description": "Explanation of why this data is needed to complete the task (max 256 characters).", - "type": "string" - } - }, - "required": [], - "type": "object" - }, - "name": "missing_data" - } - ] - GH_AW_SAFE_OUTPUTS_TOOLS_EOF - cat > /opt/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_EOF' - { - "add_comment": { - "defaultMax": 1, - "fields": { - "body": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65000 - }, - "item_number": { - "issueOrPRNumber": true - }, - "repo": { - "type": "string", - "maxLength": 256 - } - } - }, - "assign_to_agent": { - "defaultMax": 1, - "fields": { - "agent": { - "type": "string", - "sanitize": true, - "maxLength": 128 - }, - "issue_number": { - "issueNumberOrTemporaryId": true - }, - "pull_number": { - "optionalPositiveInteger": true - }, - "pull_request_repo": { - "type": "string", - "maxLength": 256 - }, - "repo": { - "type": "string", - "maxLength": 256 - } - }, - "customValidation": "requiresOneOf:issue_number,pull_number" - }, - "close_issue": { - "defaultMax": 1, - "fields": { - "body": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65000 - }, - "issue_number": { - "optionalPositiveInteger": true - }, - "repo": { - "type": "string", - "maxLength": 256 - } - } - }, - "create_issue": { - "defaultMax": 1, - "fields": { - "body": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65000 - }, - "labels": { - "type": "array", - "itemType": "string", - "itemSanitize": true, - "itemMaxLength": 128 - }, - "parent": { - "issueOrPRNumber": true - }, - "repo": { - "type": "string", - "maxLength": 256 - }, - "temporary_id": { - "type": "string" - }, - "title": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 128 - } - } - }, - "missing_data": { - "defaultMax": 20, - "fields": { - "alternatives": { - "type": "string", - "sanitize": true, - "maxLength": 256 - }, - "context": { - "type": "string", - "sanitize": true, - "maxLength": 256 - }, - "data_type": { - "type": "string", - "sanitize": true, - "maxLength": 128 - }, - "reason": { - "type": "string", - "sanitize": true, - "maxLength": 256 - } - } - }, - "missing_tool": { - "defaultMax": 20, - "fields": { - "alternatives": { - "type": "string", - "sanitize": true, - "maxLength": 512 - }, - "reason": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 256 - }, - "tool": { - "type": "string", - "sanitize": true, - "maxLength": 128 - } - } - }, - "noop": { - "defaultMax": 1, - "fields": { - "message": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65000 - } - } - } - } - GH_AW_SAFE_OUTPUTS_VALIDATION_EOF - - name: Generate Safe Outputs MCP Server Config - id: safe-outputs-config - run: | - # Generate a secure random API key (360 bits of entropy, 40+ chars) - # Mask immediately to prevent timing vulnerabilities - API_KEY=$(openssl rand -base64 45 | tr -d '/+=') - echo "::add-mask::${API_KEY}" - - PORT=3001 - - # Set outputs for next steps - { - echo "safe_outputs_api_key=${API_KEY}" - echo "safe_outputs_port=${PORT}" - } >> "$GITHUB_OUTPUT" - - echo "Safe Outputs MCP server will run on port ${PORT}" - - - name: Start Safe Outputs MCP HTTP Server - id: safe-outputs-start - env: - DEBUG: '*' - GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }} - GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }} - GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json - GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json - GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs - run: | - # Environment variables are set above to prevent template injection - export DEBUG - export GH_AW_SAFE_OUTPUTS_PORT - export GH_AW_SAFE_OUTPUTS_API_KEY - export GH_AW_SAFE_OUTPUTS_TOOLS_PATH - export GH_AW_SAFE_OUTPUTS_CONFIG_PATH - export GH_AW_MCP_LOG_DIR - - bash /opt/gh-aw/actions/start_safe_outputs_server.sh - - - name: Start MCP Gateway - id: start-mcp-gateway - env: - GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} - GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }} - GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }} - GITHUB_MCP_LOCKDOWN: ${{ steps.determine-automatic-lockdown.outputs.lockdown == 'true' && '1' || '0' }} - GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - run: | - set -eo pipefail - mkdir -p /tmp/gh-aw/mcp-config - - # Export gateway environment variables for MCP config and gateway script - export MCP_GATEWAY_PORT="80" - export MCP_GATEWAY_DOMAIN="host.docker.internal" - MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=') - echo "::add-mask::${MCP_GATEWAY_API_KEY}" - export MCP_GATEWAY_API_KEY - export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads" - mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}" - export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288" - export DEBUG="*" - - export GH_AW_ENGINE="copilot" - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_LOCKDOWN -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.1.6' - - mkdir -p /home/runner/.copilot - cat << GH_AW_MCP_CONFIG_EOF | bash /opt/gh-aw/actions/start_mcp_gateway.sh - { - "mcpServers": { - "github": { - "type": "stdio", - "container": "ghcr.io/github/github-mcp-server:v0.31.0", - "env": { - "GITHUB_LOCKDOWN_MODE": "$GITHUB_MCP_LOCKDOWN", - "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", - "GITHUB_READ_ONLY": "1", - "GITHUB_TOOLSETS": "context,repos,issues" - } - }, - "safeoutputs": { - "type": "http", - "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT", - "headers": { - "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}" - } - } - }, - "gateway": { - "port": $MCP_GATEWAY_PORT, - "domain": "${MCP_GATEWAY_DOMAIN}", - "apiKey": "${MCP_GATEWAY_API_KEY}", - "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" - } - } - GH_AW_MCP_CONFIG_EOF - - name: Download activation artifact - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 - with: - name: activation - path: /tmp/gh-aw - - name: Clean git credentials - run: bash /opt/gh-aw/actions/clean_git_credentials.sh - - name: Execute GitHub Copilot CLI - id: agentic_execution - # Copilot CLI tool arguments (sorted): - timeout-minutes: 20 - run: | - set -o pipefail - # shellcheck disable=SC1003 - sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \ - -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"}' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log - env: - COPILOT_AGENT_RUNNER_TYPE: STANDALONE - COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json - GH_AW_MODEL_AGENT_COPILOT: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} - GITHUB_API_URL: ${{ github.api_url }} - GITHUB_HEAD_REF: ${{ github.head_ref }} - GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - GITHUB_REF_NAME: ${{ github.ref_name }} - GITHUB_SERVER_URL: ${{ github.server_url }} - GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} - GITHUB_WORKSPACE: ${{ github.workspace }} - XDG_CONFIG_HOME: /home/runner - - name: Configure Git credentials - env: - REPO_NAME: ${{ github.repository }} - SERVER_URL: ${{ github.server_url }} - run: | - git config --global user.email "github-actions[bot]@users.noreply.github.com" - git config --global user.name "github-actions[bot]" - git config --global am.keepcr true - # Re-authenticate git with GitHub token - SERVER_URL_STRIPPED="${SERVER_URL#https://}" - git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" - echo "Git configured with standard GitHub Actions identity" - - name: Copy Copilot session state files to logs - if: always() - continue-on-error: true - run: | - # Copy Copilot session state files to logs folder for artifact collection - # This ensures they are in /tmp/gh-aw/ where secret redaction can scan them - SESSION_STATE_DIR="$HOME/.copilot/session-state" - LOGS_DIR="/tmp/gh-aw/sandbox/agent/logs" - - if [ -d "$SESSION_STATE_DIR" ]; then - echo "Copying Copilot session state files from $SESSION_STATE_DIR to $LOGS_DIR" - mkdir -p "$LOGS_DIR" - cp -v "$SESSION_STATE_DIR"/*.jsonl "$LOGS_DIR/" 2>/dev/null || true - echo "Session state files copied successfully" - else - echo "No session-state directory found at $SESSION_STATE_DIR" - fi - - name: Stop MCP Gateway - if: always() - continue-on-error: true - env: - MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }} - MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }} - GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }} - run: | - bash /opt/gh-aw/actions/stop_mcp_gateway.sh "$GATEWAY_PID" - - name: Redact secrets in logs - if: always() - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/redact_secrets.cjs'); - await main(); - env: - GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' - SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} - SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} - SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Upload Safe Outputs - if: always() - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 - with: - name: safe-output - path: ${{ env.GH_AW_SAFE_OUTPUTS }} - if-no-files-found: warn - - name: Ingest agent output - id: collect_output - if: always() - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" - GITHUB_SERVER_URL: ${{ github.server_url }} - GITHUB_API_URL: ${{ github.api_url }} - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/collect_ndjson_output.cjs'); - await main(); - - name: Upload sanitized agent output - if: always() && env.GH_AW_AGENT_OUTPUT - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 - with: - name: agent-output - path: ${{ env.GH_AW_AGENT_OUTPUT }} - if-no-files-found: warn - - name: Upload engine output files - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 - with: - name: agent_outputs - path: | - /tmp/gh-aw/sandbox/agent/logs/ - /tmp/gh-aw/redacted-urls.log - if-no-files-found: ignore - - name: Parse agent logs for step summary - if: always() - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/ - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/parse_copilot_log.cjs'); - await main(); - - name: Parse MCP Gateway logs for step summary - if: always() - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/parse_mcp_gateway_log.cjs'); - await main(); - - name: Print firewall logs - if: always() - continue-on-error: true - env: - AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs - run: | - # Fix permissions on firewall logs so they can be uploaded as artifacts - # AWF runs with sudo, creating files owned by root - sudo chmod -R a+r /tmp/gh-aw/sandbox/firewall/logs 2>/dev/null || true - # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step) - if command -v awf &> /dev/null; then - awf logs summary | tee -a "$GITHUB_STEP_SUMMARY" - else - echo 'AWF binary not installed, skipping firewall log summary' - fi - - name: Upload agent artifacts - if: always() - continue-on-error: true - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 - with: - name: agent-artifacts - path: | - /tmp/gh-aw/aw-prompts/prompt.txt - /tmp/gh-aw/mcp-logs/ - /tmp/gh-aw/sandbox/firewall/logs/ - /tmp/gh-aw/agent-stdio.log - /tmp/gh-aw/agent/ - if-no-files-found: ignore - # --- Threat Detection (inline) --- - - name: Check if detection needed - id: detection_guard - if: always() - env: - OUTPUT_TYPES: ${{ steps.collect_output.outputs.output_types }} - HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }} - run: | - if [[ -n "$OUTPUT_TYPES" || "$HAS_PATCH" == "true" ]]; then - echo "run_detection=true" >> "$GITHUB_OUTPUT" - echo "Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH" - else - echo "run_detection=false" >> "$GITHUB_OUTPUT" - echo "Detection skipped: no agent outputs or patches to analyze" - fi - - name: Clear MCP configuration for detection - if: always() && steps.detection_guard.outputs.run_detection == 'true' - run: | - rm -f /tmp/gh-aw/mcp-config/mcp-servers.json - rm -f /home/runner/.copilot/mcp-config.json - rm -f "$GITHUB_WORKSPACE/.gemini/settings.json" - - name: Prepare threat detection files - if: always() && steps.detection_guard.outputs.run_detection == 'true' - run: | - mkdir -p /tmp/gh-aw/threat-detection/aw-prompts - cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true - cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true - for f in /tmp/gh-aw/aw-*.patch; do - [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true - done - echo "Prepared threat detection files:" - ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true - - name: Setup threat detection - if: always() && steps.detection_guard.outputs.run_detection == 'true' - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - WORKFLOW_NAME: "Weekly Upstream Sync Agentic Workflow" - WORKFLOW_DESCRIPTION: "Weekly upstream sync workflow. Checks for new commits in the official\nCopilot SDK (github/copilot-sdk) and assigns to Copilot to port changes." - HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }} - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/setup_threat_detection.cjs'); - await main(); - - name: Ensure threat-detection directory and log - if: always() && steps.detection_guard.outputs.run_detection == 'true' - run: | - mkdir -p /tmp/gh-aw/threat-detection - touch /tmp/gh-aw/threat-detection/detection.log - - name: Execute GitHub Copilot CLI - if: always() && steps.detection_guard.outputs.run_detection == 'true' - id: detection_agentic_execution - # Copilot CLI tool arguments (sorted): - # --allow-tool shell(cat) - # --allow-tool shell(grep) - # --allow-tool shell(head) - # --allow-tool shell(jq) - # --allow-tool shell(ls) - # --allow-tool shell(tail) - # --allow-tool shell(wc) - timeout-minutes: 20 - run: | - set -o pipefail - # shellcheck disable=SC1003 - sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,raw.githubusercontent.com,registry.npmjs.org,telemetry.enterprise.githubcopilot.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \ - -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(wc)'\'' --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_DETECTION_COPILOT:+ --model "$GH_AW_MODEL_DETECTION_COPILOT"}' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log - env: - COPILOT_AGENT_RUNNER_TYPE: STANDALONE - COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - GH_AW_MODEL_DETECTION_COPILOT: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }} - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GITHUB_API_URL: ${{ github.api_url }} - GITHUB_HEAD_REF: ${{ github.head_ref }} - GITHUB_REF_NAME: ${{ github.ref_name }} - GITHUB_SERVER_URL: ${{ github.server_url }} - GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} - GITHUB_WORKSPACE: ${{ github.workspace }} - XDG_CONFIG_HOME: /home/runner - - name: Parse threat detection results - id: parse_detection_results - if: always() && steps.detection_guard.outputs.run_detection == 'true' - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/parse_threat_detection_results.cjs'); - await main(); - - name: Upload threat detection log - if: always() && steps.detection_guard.outputs.run_detection == 'true' - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 - with: - name: threat-detection.log - path: /tmp/gh-aw/threat-detection/detection.log - if-no-files-found: ignore - - name: Set detection conclusion - id: detection_conclusion - if: always() - env: - RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }} - DETECTION_SUCCESS: ${{ steps.parse_detection_results.outputs.success }} - run: | - if [[ "$RUN_DETECTION" != "true" ]]; then - echo "conclusion=skipped" >> "$GITHUB_OUTPUT" - echo "success=true" >> "$GITHUB_OUTPUT" - echo "Detection was not needed, marking as skipped" - elif [[ "$DETECTION_SUCCESS" == "true" ]]; then - echo "conclusion=success" >> "$GITHUB_OUTPUT" - echo "success=true" >> "$GITHUB_OUTPUT" - echo "Detection passed successfully" - else - echo "conclusion=failure" >> "$GITHUB_OUTPUT" - echo "success=false" >> "$GITHUB_OUTPUT" - echo "Detection found issues" - fi - - conclusion: - needs: - - activation - - agent - - safe_outputs - if: (always()) && (needs.agent.result != 'skipped') - runs-on: ubuntu-slim - permissions: - contents: read - discussions: write - issues: write - pull-requests: write - outputs: - noop_message: ${{ steps.noop.outputs.noop_message }} - tools_reported: ${{ steps.missing_tool.outputs.tools_reported }} - total_count: ${{ steps.missing_tool.outputs.total_count }} - steps: - - name: Setup Scripts - uses: github/gh-aw/actions/setup@33cd6c7f1fee588654ef19def2e6a4174be66197 # v0.51.6 - with: - destination: /opt/gh-aw/actions - - name: Download agent output artifact - continue-on-error: true - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 - with: - name: agent-output - path: /tmp/gh-aw/safeoutputs/ - - name: Setup agent output environment variable - run: | - mkdir -p /tmp/gh-aw/safeoutputs/ - find "/tmp/gh-aw/safeoutputs/" -type f -print - echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" - - name: Process No-Op Messages - id: noop - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_NOOP_MAX: "1" - GH_AW_WORKFLOW_NAME: "Weekly Upstream Sync Agentic Workflow" - with: - github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/noop.cjs'); - await main(); - - name: Record Missing Tool - id: missing_tool - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_WORKFLOW_NAME: "Weekly Upstream Sync Agentic Workflow" - with: - github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/missing_tool.cjs'); - await main(); - - name: Handle Agent Failure - id: handle_agent_failure - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_WORKFLOW_NAME: "Weekly Upstream Sync Agentic Workflow" - GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} - GH_AW_WORKFLOW_ID: "weekly-upstream-sync" - GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} - GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} - GH_AW_ASSIGNMENT_ERRORS: ${{ needs.safe_outputs.outputs.assign_to_agent_assignment_errors }} - GH_AW_ASSIGNMENT_ERROR_COUNT: ${{ needs.safe_outputs.outputs.assign_to_agent_assignment_error_count }} - GH_AW_GROUP_REPORTS: "false" - with: - github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/handle_agent_failure.cjs'); - await main(); - - name: Handle No-Op Message - id: handle_noop_message - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_WORKFLOW_NAME: "Weekly Upstream Sync Agentic Workflow" - GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} - GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }} - GH_AW_NOOP_REPORT_AS_ISSUE: "false" - with: - github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/handle_noop_message.cjs'); - await main(); - - safe_outputs: - needs: agent - if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.agent.outputs.detection_success == 'true') - runs-on: ubuntu-slim - permissions: - contents: read - discussions: write - issues: write - pull-requests: write - timeout-minutes: 15 - env: - GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/${{ github.workflow }}" - GH_AW_ENGINE_ID: "copilot" - GH_AW_WORKFLOW_ID: "weekly-upstream-sync" - GH_AW_WORKFLOW_NAME: "Weekly Upstream Sync Agentic Workflow" - outputs: - assign_to_agent_assigned: ${{ steps.assign_to_agent.outputs.assigned }} - assign_to_agent_assignment_error_count: ${{ steps.assign_to_agent.outputs.assignment_error_count }} - assign_to_agent_assignment_errors: ${{ steps.assign_to_agent.outputs.assignment_errors }} - code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }} - code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }} - comment_id: ${{ steps.process_safe_outputs.outputs.comment_id }} - comment_url: ${{ steps.process_safe_outputs.outputs.comment_url }} - create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }} - create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }} - created_issue_number: ${{ steps.process_safe_outputs.outputs.created_issue_number }} - created_issue_url: ${{ steps.process_safe_outputs.outputs.created_issue_url }} - process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }} - process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} - steps: - - name: Setup Scripts - uses: github/gh-aw/actions/setup@33cd6c7f1fee588654ef19def2e6a4174be66197 # v0.51.6 - with: - destination: /opt/gh-aw/actions - - name: Download agent output artifact - continue-on-error: true - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 - with: - name: agent-output - path: /tmp/gh-aw/safeoutputs/ - - name: Setup agent output environment variable - run: | - mkdir -p /tmp/gh-aw/safeoutputs/ - find "/tmp/gh-aw/safeoutputs/" -type f -print - echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" - - name: Process Safe Outputs - id: process_safe_outputs - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" - GITHUB_SERVER_URL: ${{ github.server_url }} - GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":10,\"target\":\"*\"},\"close_issue\":{\"max\":10,\"required_labels\":[\"upstream-sync\"],\"target\":\"*\"},\"create_issue\":{\"assignees\":[\"copilot\"],\"expires\":144,\"labels\":[\"upstream-sync\"],\"max\":1,\"title_prefix\":\"[upstream-sync] \"},\"missing_data\":{},\"missing_tool\":{}}" - GH_AW_ASSIGN_COPILOT: "true" - with: - github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/safe_output_handler_manager.cjs'); - await main(); - - name: Assign Copilot to created issues - if: steps.process_safe_outputs.outputs.issues_to_assign_copilot != '' - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_ISSUES_TO_ASSIGN_COPILOT: ${{ steps.process_safe_outputs.outputs.issues_to_assign_copilot }} - with: - github-token: ${{ secrets.GH_AW_AGENT_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/assign_copilot_to_created_issues.cjs'); - await main(); - - name: Assign to agent - id: assign_to_agent - if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'assign_to_agent')) - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_AGENT_MAX_COUNT: 1 - GH_AW_AGENT_DEFAULT: "copilot" - GH_AW_AGENT_DEFAULT_MODEL: "claude-opus-4.6" - GH_AW_AGENT_TARGET: "*" - GH_AW_TEMPORARY_ID_MAP: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} - with: - github-token: ${{ secrets.GH_AW_AGENT_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/assign_to_agent.cjs'); - await main(); - - name: Upload safe output items manifest - if: always() - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 - with: - name: safe-output-items - path: /tmp/safe-output-items.jsonl - if-no-files-found: warn - diff --git a/.github/workflows/weekly-upstream-sync.md b/.github/workflows/weekly-upstream-sync.md deleted file mode 100644 index 0aaff8d1e..000000000 --- a/.github/workflows/weekly-upstream-sync.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -description: | - Weekly upstream sync workflow. Checks for new commits in the official - Copilot SDK (github/copilot-sdk) and assigns to Copilot to port changes. - -on: - schedule: weekly - workflow_dispatch: - -permissions: - contents: read - actions: read - issues: read - -network: - allowed: - - defaults - - github - -tools: - github: - toolsets: [context, repos, issues] - -safe-outputs: - create-issue: - title-prefix: "[upstream-sync] " - assignees: [copilot] - labels: [upstream-sync] - expires: 6 - close-issue: - required-labels: [upstream-sync] - target: "*" - max: 10 - add-comment: - target: "*" - max: 10 - assign-to-agent: - name: "copilot" - model: "claude-opus-4.6" - target: "*" - noop: - report-as-issue: false ---- -# Weekly Upstream Sync - -You are an automation agent that detects new upstream changes and creates GitHub issues. You do **NOT** perform any code merges, edits, or pushes. Do **NOT** invoke any skills (especially `agentic-merge-upstream`). Your only job is to check for changes and use safe-output tools to create or close issues. - -## Instructions - -Follow these steps exactly: - -### Step 1: Read `.lastmerge` - -Read the file `.lastmerge` in the repository root. It contains the SHA of the last upstream commit that was merged into this Java SDK. - -### Step 2: Check for upstream changes - -Clone the upstream repository and compare commits: - -```bash -LAST_MERGE=$(cat .lastmerge) -git clone --quiet https://github.com/github/copilot-sdk.git /tmp/gh-aw/agent/upstream -cd /tmp/gh-aw/agent/upstream -UPSTREAM_HEAD=$(git rev-parse HEAD) -``` - -If `LAST_MERGE` equals `UPSTREAM_HEAD`, there are **no new changes**. Go to Step 3a. - -If they differ, count the new commits and generate a summary: - -```bash -COMMIT_COUNT=$(git rev-list --count "$LAST_MERGE".."$UPSTREAM_HEAD") -SUMMARY=$(git log --oneline "$LAST_MERGE".."$UPSTREAM_HEAD" | head -20) -``` - -Go to Step 3b. - -### Step 3a: No changes detected - -1. Search for any open issues with the `upstream-sync` label using the GitHub MCP tools. -2. If there are open `upstream-sync` issues, close each one using the `close_issue` safe-output tool with a comment: "No new upstream changes detected. The Java SDK is up to date. Closing." -3. Call the `noop` safe-output tool with message: "No new upstream changes since last merge ()." -4. **Stop here.** Do not proceed further. - -### Step 3b: Changes detected - -1. Search for any open issues with the `upstream-sync` label using the GitHub MCP tools. -2. Close each existing open `upstream-sync` issue using the `close_issue` safe-output tool with a comment: "Superseded by a newer upstream sync check." -3. Create a new issue using the `create_issue` safe-output tool with: - - **Title:** `Upstream sync: new commits ()` - - **Body:** Include the following information: - ``` - ## Automated Upstream Sync - - There are **** new commits in the [official Copilot SDK](https://github.com/github/copilot-sdk) since the last merge. - - - **Last merged commit:** [``](https://github.com/github/copilot-sdk/commit/) - - **Upstream HEAD:** [``](https://github.com/github/copilot-sdk/commit/) - - ### Recent upstream commits - - ``` - - ``` - - ### Instructions - - Follow the [agentic-merge-upstream](.github/prompts/agentic-merge-upstream.prompt.md) prompt to port these changes to the Java SDK. - ``` -4. After creating the issue, use the `assign_to_agent` safe-output tool to assign Copilot to the newly created issue. - -## Important constraints - -- **Do NOT edit any files**, create branches, or push code. -- **Do NOT invoke any skills** such as `agentic-merge-upstream` or `commit-as-pull-request`. -- **Do NOT attempt to merge or port upstream changes.** That is done by a separate agent that picks up the issue you create. -- You **MUST** call at least one safe-output tool (`create_issue`, `close_issue`, `noop`, etc.) before finishing. diff --git a/.github/workflows/weekly-upstream-sync.yml b/.github/workflows/weekly-upstream-sync.yml deleted file mode 100644 index 5281fa032..000000000 --- a/.github/workflows/weekly-upstream-sync.yml +++ /dev/null @@ -1,181 +0,0 @@ -name: "Weekly Upstream Sync" - -on: - schedule: - # Every Monday at 10:00 UTC (5:00 AM EST / 6:00 AM EDT) - - cron: '0 10 * * 1' - workflow_dispatch: - -permissions: - contents: write - issues: write - pull-requests: write - -env: - # Used for `gh` CLI operations to create/close/comment issues. Must be a PAT with repo permissions because the default - GH_AW_AGENT_TOKEN: ${{ secrets.GH_AW_AGENT_TOKEN }} - GH_TOKEN: ${{ secrets.GH_AW_AGENT_TOKEN }} - -jobs: - - check-and-sync: - name: "Check upstream & trigger Copilot merge" - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Check for upstream changes - id: check - run: | - LAST_MERGE=$(cat .lastmerge) - echo "Last merged commit: $LAST_MERGE" - - git clone --quiet https://github.com/github/copilot-sdk.git /tmp/upstream - cd /tmp/upstream - - UPSTREAM_HEAD=$(git rev-parse HEAD) - echo "Upstream HEAD: $UPSTREAM_HEAD" - - echo "last_merge=$LAST_MERGE" >> "$GITHUB_OUTPUT" - - if [ "$LAST_MERGE" = "$UPSTREAM_HEAD" ]; then - echo "No new upstream changes since last merge." - echo "has_changes=false" >> "$GITHUB_OUTPUT" - else - COMMIT_COUNT=$(git rev-list --count "$LAST_MERGE".."$UPSTREAM_HEAD") - echo "Found $COMMIT_COUNT new upstream commits." - echo "has_changes=true" >> "$GITHUB_OUTPUT" - echo "commit_count=$COMMIT_COUNT" >> "$GITHUB_OUTPUT" - echo "upstream_head=$UPSTREAM_HEAD" >> "$GITHUB_OUTPUT" - - # Generate a short summary of changes - SUMMARY=$(git log --oneline "$LAST_MERGE".."$UPSTREAM_HEAD" | head -20) - { - echo "summary<> "$GITHUB_OUTPUT" - fi - - - name: Close previous upstream-sync issues - if: steps.check.outputs.has_changes == 'true' - run: | - # Find all open issues with the upstream-sync label - OPEN_ISSUES=$(gh issue list \ - --repo "${{ github.repository }}" \ - --label "upstream-sync" \ - --state open \ - --json number \ - --jq '.[].number') - - for ISSUE_NUM in $OPEN_ISSUES; do - echo "Closing superseded issue #${ISSUE_NUM}" - gh issue comment "$ISSUE_NUM" \ - --repo "${{ github.repository }}" \ - --body "Superseded by a newer upstream sync issue. Closing this one." - gh issue close "$ISSUE_NUM" \ - --repo "${{ github.repository }}" \ - --reason "not planned" - done - - - name: Close stale upstream-sync issues (no changes) - if: steps.check.outputs.has_changes == 'false' - run: | - OPEN_ISSUES=$(gh issue list \ - --repo "${{ github.repository }}" \ - --label "upstream-sync" \ - --state open \ - --json number \ - --jq '.[].number') - - for ISSUE_NUM in $OPEN_ISSUES; do - echo "Closing stale issue #${ISSUE_NUM} — upstream is up to date" - gh issue comment "$ISSUE_NUM" \ - --repo "${{ github.repository }}" \ - --body "No new upstream changes detected. The Java SDK is up to date. Closing." - gh issue close "$ISSUE_NUM" \ - --repo "${{ github.repository }}" \ - --reason "completed" - done - - - name: Create issue and assign to Copilot - id: create-issue - if: steps.check.outputs.has_changes == 'true' - env: - SUMMARY: ${{ steps.check.outputs.summary }} - run: | - COMMIT_COUNT="${{ steps.check.outputs.commit_count }}" - LAST_MERGE="${{ steps.check.outputs.last_merge }}" - UPSTREAM_HEAD="${{ steps.check.outputs.upstream_head }}" - DATE=$(date -u +"%Y-%m-%d") - REPO="${{ github.repository }}" - - BODY="## Automated Upstream Sync - - There are **${COMMIT_COUNT}** new commits in the [official Copilot SDK](https://github.com/github/copilot-sdk) since the last merge. - - - **Last merged commit:** [\`${LAST_MERGE}\`](https://github.com/github/copilot-sdk/commit/${LAST_MERGE}) - - **Upstream HEAD:** [\`${UPSTREAM_HEAD}\`](https://github.com/github/copilot-sdk/commit/${UPSTREAM_HEAD}) - - ### Recent upstream commits - - \`\`\` - ${SUMMARY} - \`\`\` - - ### Instructions - - Follow the [agentic-merge-upstream](.github/prompts/agentic-merge-upstream.prompt.md) prompt to port these changes to the Java SDK." - - # Create the issue and assign to Copilot coding agent - ISSUE_URL=$(gh issue create \ - --repo "$REPO" \ - --title "Upstream sync: ${COMMIT_COUNT} new commits (${DATE})" \ - --body "$BODY" \ - --label "upstream-sync" \ - --assignee "copilot-swe-agent") - - echo "issue_url=$ISSUE_URL" >> "$GITHUB_OUTPUT" - echo "✅ Issue created and assigned to Copilot coding agent: $ISSUE_URL" - - - name: Summary - if: always() - env: - SUMMARY: ${{ steps.check.outputs.summary }} - run: | - HAS_CHANGES="${{ steps.check.outputs.has_changes }}" - COMMIT_COUNT="${{ steps.check.outputs.commit_count }}" - LAST_MERGE="${{ steps.check.outputs.last_merge }}" - UPSTREAM_HEAD="${{ steps.check.outputs.upstream_head }}" - ISSUE_URL="${{ steps.create-issue.outputs.issue_url }}" - - { - echo "## Weekly Upstream Sync" - echo "" - if [ "$HAS_CHANGES" = "true" ]; then - echo "### ✅ New upstream changes detected" - echo "" - echo "| | |" - echo "|---|---|" - echo "| **New commits** | ${COMMIT_COUNT} |" - echo "| **Last merged** | \`${LAST_MERGE:0:12}\` |" - echo "| **Upstream HEAD** | \`${UPSTREAM_HEAD:0:12}\` |" - echo "" - echo "An issue has been created and assigned to the Copilot coding agent: " - echo " -> ${ISSUE_URL}" - echo "" - echo "### Recent upstream commits" - echo "" - echo '```' - echo "$SUMMARY" - echo '```' - else - echo "### ⏭️ No changes" - echo "" - echo "The Java SDK is already up to date with the upstream Copilot SDK." - echo "" - echo "**Last merged commit:** \`${LAST_MERGE:0:12}\`" - fi - } >> "$GITHUB_STEP_SUMMARY" diff --git a/CHANGELOG.md b/CHANGELOG.md index 38f6e6589..130bc5105 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,17 +8,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Unreleased] -> **Upstream sync:** [`github/copilot-sdk@c3fa6cb`](https://github.com/github/copilot-sdk/commit/c3fa6cbfb83d4a20b7912b1a17013d48f5a277a1) +> **Reference implementation sync:** [`github/copilot-sdk@c3fa6cb`](https://github.com/github/copilot-sdk/commit/c3fa6cbfb83d4a20b7912b1a17013d48f5a277a1) ## [0.2.2-java.1] - 2026-04-07 -> **Upstream sync:** [`github/copilot-sdk@c3fa6cb`](https://github.com/github/copilot-sdk/commit/c3fa6cbfb83d4a20b7912b1a17013d48f5a277a1) +> **Reference implementation sync:** [`github/copilot-sdk@c3fa6cb`](https://github.com/github/copilot-sdk/commit/c3fa6cbfb83d4a20b7912b1a17013d48f5a277a1) ### Added -- Slash commands — register `/command` handlers invoked from the CLI TUI via `SessionConfig.setCommands()` (upstream: [`f7fd757`](https://github.com/github/copilot-sdk/commit/f7fd757)) +- Slash commands — register `/command` handlers invoked from the CLI TUI via `SessionConfig.setCommands()` (reference implementation: [`f7fd757`](https://github.com/github/copilot-sdk/commit/f7fd757)) - `CommandDefinition`, `CommandContext`, `CommandHandler`, `CommandWireDefinition` — types for defining and handling slash commands - `CommandExecuteEvent` — event dispatched when a registered slash command is executed -- Elicitation (UI dialogs) — incoming handler via `SessionConfig.setOnElicitationRequest()` and outgoing convenience methods via `session.getUi()` (upstream: [`f7fd757`](https://github.com/github/copilot-sdk/commit/f7fd757)) +- Elicitation (UI dialogs) — incoming handler via `SessionConfig.setOnElicitationRequest()` and outgoing convenience methods via `session.getUi()` (reference implementation: [`f7fd757`](https://github.com/github/copilot-sdk/commit/f7fd757)) - `ElicitationContext`, `ElicitationHandler`, `ElicitationParams`, `ElicitationResult`, `ElicitationResultAction`, `ElicitationSchema`, `InputOptions` — types for elicitation - `ElicitationRequestedEvent` — event dispatched when an elicitation request is received - `SessionUiApi` — convenience API on `session.getUi()` for `confirm()`, `select()`, `input()`, and `elicitation()` calls @@ -35,27 +35,27 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [0.2.1-java.1] - 2026-04-02 -> **Upstream sync:** [`github/copilot-sdk@4088739`](https://github.com/github/copilot-sdk/commit/40887393a9e687dacc141a645799441b0313ff15) +> **Reference implementation sync:** [`github/copilot-sdk@4088739`](https://github.com/github/copilot-sdk/commit/40887393a9e687dacc141a645799441b0313ff15) ## [0.2.1-java.0] - 2026-03-26 -> **Upstream sync:** [`github/copilot-sdk@4088739`](https://github.com/github/copilot-sdk/commit/40887393a9e687dacc141a645799441b0313ff15) +> **Reference implementation sync:** [`github/copilot-sdk@4088739`](https://github.com/github/copilot-sdk/commit/40887393a9e687dacc141a645799441b0313ff15) ### Added -- `UnknownSessionEvent` — forward-compatible placeholder for event types not yet known to the SDK; unknown events are now dispatched to handlers instead of being silently dropped (upstream: [`d82fd62`](https://github.com/github/copilot-sdk/commit/d82fd62)) -- `PermissionRequestResultKind.NO_RESULT` — new constant that signals the handler intentionally abstains from answering a permission request, leaving it unanswered for another client (upstream: [`df59a0e`](https://github.com/github/copilot-sdk/commit/df59a0e)) -- `ToolDefinition.skipPermission` field and `ToolDefinition.createSkipPermission()` factory — marks a tool to skip the permission prompt (upstream: [`10c4d02`](https://github.com/github/copilot-sdk/commit/10c4d02)) -- `SystemMessageMode.CUSTOMIZE` — new enum value for fine-grained system prompt customization (upstream: [`005b780`](https://github.com/github/copilot-sdk/commit/005b780)) -- `SectionOverrideAction` enum — specifies the operation on a system prompt section (replace, remove, append, prepend, transform) (upstream: [`005b780`](https://github.com/github/copilot-sdk/commit/005b780)) -- `SectionOverride` class — describes how one section of the system prompt should be modified, with optional transform callback (upstream: [`005b780`](https://github.com/github/copilot-sdk/commit/005b780)) -- `SystemPromptSections` constants — well-known section identifier strings for use with CUSTOMIZE mode (upstream: [`005b780`](https://github.com/github/copilot-sdk/commit/005b780)) -- `SystemMessageConfig.setSections(Map)` — section-level overrides for CUSTOMIZE mode (upstream: [`005b780`](https://github.com/github/copilot-sdk/commit/005b780)) -- `systemMessage.transform` RPC handler — the SDK now registers a handler that invokes transform callbacks registered in the session config (upstream: [`005b780`](https://github.com/github/copilot-sdk/commit/005b780)) -- `CopilotSession.setModel(String, String)` — new overload that accepts an optional reasoning effort level (upstream: [`ea90f07`](https://github.com/github/copilot-sdk/commit/ea90f07)) +- `UnknownSessionEvent` — forward-compatible placeholder for event types not yet known to the SDK; unknown events are now dispatched to handlers instead of being silently dropped (reference implementation: [`d82fd62`](https://github.com/github/copilot-sdk/commit/d82fd62)) +- `PermissionRequestResultKind.NO_RESULT` — new constant that signals the handler intentionally abstains from answering a permission request, leaving it unanswered for another client (reference implementation: [`df59a0e`](https://github.com/github/copilot-sdk/commit/df59a0e)) +- `ToolDefinition.skipPermission` field and `ToolDefinition.createSkipPermission()` factory — marks a tool to skip the permission prompt (reference implementation: [`10c4d02`](https://github.com/github/copilot-sdk/commit/10c4d02)) +- `SystemMessageMode.CUSTOMIZE` — new enum value for fine-grained system prompt customization (reference implementation: [`005b780`](https://github.com/github/copilot-sdk/commit/005b780)) +- `SectionOverrideAction` enum — specifies the operation on a system prompt section (replace, remove, append, prepend, transform) (reference implementation: [`005b780`](https://github.com/github/copilot-sdk/commit/005b780)) +- `SectionOverride` class — describes how one section of the system prompt should be modified, with optional transform callback (reference implementation: [`005b780`](https://github.com/github/copilot-sdk/commit/005b780)) +- `SystemPromptSections` constants — well-known section identifier strings for use with CUSTOMIZE mode (reference implementation: [`005b780`](https://github.com/github/copilot-sdk/commit/005b780)) +- `SystemMessageConfig.setSections(Map)` — section-level overrides for CUSTOMIZE mode (reference implementation: [`005b780`](https://github.com/github/copilot-sdk/commit/005b780)) +- `systemMessage.transform` RPC handler — the SDK now registers a handler that invokes transform callbacks registered in the session config (reference implementation: [`005b780`](https://github.com/github/copilot-sdk/commit/005b780)) +- `CopilotSession.setModel(String, String)` — new overload that accepts an optional reasoning effort level (reference implementation: [`ea90f07`](https://github.com/github/copilot-sdk/commit/ea90f07)) - `CopilotSession.log(String, String, Boolean, String)` — new overload with an optional `url` parameter (minor addition) -- `BlobAttachment` class — inline base64-encoded binary attachment for messages (e.g., images) (upstream: [`698b259`](https://github.com/github/copilot-sdk/commit/698b259)) +- `BlobAttachment` class — inline base64-encoded binary attachment for messages (e.g., images) (reference implementation: [`698b259`](https://github.com/github/copilot-sdk/commit/698b259)) - `MessageAttachment` sealed interface — type-safe base for all attachment types (`Attachment`, `BlobAttachment`), with Jackson polymorphic serialization support -- `TelemetryConfig` class — OpenTelemetry configuration for the CLI server; set on `CopilotClientOptions.setTelemetry()` (upstream: [`f2d21a0`](https://github.com/github/copilot-sdk/commit/f2d21a0)) -- `CopilotClientOptions.setTelemetry(TelemetryConfig)` — enables OpenTelemetry instrumentation in the CLI server (upstream: [`f2d21a0`](https://github.com/github/copilot-sdk/commit/f2d21a0)) +- `TelemetryConfig` class — OpenTelemetry configuration for the CLI server; set on `CopilotClientOptions.setTelemetry()` (reference implementation: [`f2d21a0`](https://github.com/github/copilot-sdk/commit/f2d21a0)) +- `CopilotClientOptions.setTelemetry(TelemetryConfig)` — enables OpenTelemetry instrumentation in the CLI server (reference implementation: [`f2d21a0`](https://github.com/github/copilot-sdk/commit/f2d21a0)) ### Changed @@ -70,61 +70,61 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [0.1.32-java.0] - 2026-03-17 -> **Upstream sync:** [`github/copilot-sdk@062b61c`](https://github.com/github/copilot-sdk/commit/062b61c8aa63b9b5d45fa1d7b01723e6660ffa83) +> **Reference implementation sync:** [`github/copilot-sdk@062b61c`](https://github.com/github/copilot-sdk/commit/062b61c8aa63b9b5d45fa1d7b01723e6660ffa83) ## [1.0.11] - 2026-03-12 -> **Upstream sync:** [`github/copilot-sdk@062b61c`](https://github.com/github/copilot-sdk/commit/062b61c8aa63b9b5d45fa1d7b01723e6660ffa83) +> **Reference implementation sync:** [`github/copilot-sdk@062b61c`](https://github.com/github/copilot-sdk/commit/062b61c8aa63b9b5d45fa1d7b01723e6660ffa83) ### Added -- `CopilotClientOptions.setOnListModels(Supplier>>)` — custom handler for `listModels()` used in BYOK mode to return models from a custom provider instead of querying the CLI (upstream: [`e478657`](https://github.com/github/copilot-sdk/commit/e478657)) -- `SessionConfig.setAgent(String)` — pre-selects a custom agent by name when creating a session (upstream: [`7766b1a`](https://github.com/github/copilot-sdk/commit/7766b1a)) -- `ResumeSessionConfig.setAgent(String)` — pre-selects a custom agent by name when resuming a session (upstream: [`7766b1a`](https://github.com/github/copilot-sdk/commit/7766b1a)) -- `SessionConfig.setOnEvent(Consumer)` — registers an event handler before the `session.create` RPC is issued, ensuring no early events are missed (upstream: [`4125fe7`](https://github.com/github/copilot-sdk/commit/4125fe7)) -- `ResumeSessionConfig.setOnEvent(Consumer)` — registers an event handler before the `session.resume` RPC is issued (upstream: [`4125fe7`](https://github.com/github/copilot-sdk/commit/4125fe7)) -- New broadcast session event types (protocol v3): `ExternalToolRequestedEvent` (`external_tool.requested`), `ExternalToolCompletedEvent` (`external_tool.completed`), `PermissionRequestedEvent` (`permission.requested`), `PermissionCompletedEvent` (`permission.completed`), `CommandQueuedEvent` (`command.queued`), `CommandCompletedEvent` (`command.completed`), `ExitPlanModeRequestedEvent` (`exit_plan_mode.requested`), `ExitPlanModeCompletedEvent` (`exit_plan_mode.completed`), `SystemNotificationEvent` (`system.notification`) (upstream: [`1653812`](https://github.com/github/copilot-sdk/commit/1653812), [`396e8b3`](https://github.com/github/copilot-sdk/commit/396e8b3)) -- `CopilotSession.log(String)` and `CopilotSession.log(String, String, Boolean)` — log a message to the session timeline (upstream: [`4125fe7`](https://github.com/github/copilot-sdk/commit/4125fe7)) +- `CopilotClientOptions.setOnListModels(Supplier>>)` — custom handler for `listModels()` used in BYOK mode to return models from a custom provider instead of querying the CLI (reference implementation: [`e478657`](https://github.com/github/copilot-sdk/commit/e478657)) +- `SessionConfig.setAgent(String)` — pre-selects a custom agent by name when creating a session (reference implementation: [`7766b1a`](https://github.com/github/copilot-sdk/commit/7766b1a)) +- `ResumeSessionConfig.setAgent(String)` — pre-selects a custom agent by name when resuming a session (reference implementation: [`7766b1a`](https://github.com/github/copilot-sdk/commit/7766b1a)) +- `SessionConfig.setOnEvent(Consumer)` — registers an event handler before the `session.create` RPC is issued, ensuring no early events are missed (reference implementation: [`4125fe7`](https://github.com/github/copilot-sdk/commit/4125fe7)) +- `ResumeSessionConfig.setOnEvent(Consumer)` — registers an event handler before the `session.resume` RPC is issued (reference implementation: [`4125fe7`](https://github.com/github/copilot-sdk/commit/4125fe7)) +- New broadcast session event types (protocol v3): `ExternalToolRequestedEvent` (`external_tool.requested`), `ExternalToolCompletedEvent` (`external_tool.completed`), `PermissionRequestedEvent` (`permission.requested`), `PermissionCompletedEvent` (`permission.completed`), `CommandQueuedEvent` (`command.queued`), `CommandCompletedEvent` (`command.completed`), `ExitPlanModeRequestedEvent` (`exit_plan_mode.requested`), `ExitPlanModeCompletedEvent` (`exit_plan_mode.completed`), `SystemNotificationEvent` (`system.notification`) (reference implementation: [`1653812`](https://github.com/github/copilot-sdk/commit/1653812), [`396e8b3`](https://github.com/github/copilot-sdk/commit/396e8b3)) +- `CopilotSession.log(String)` and `CopilotSession.log(String, String, Boolean)` — log a message to the session timeline (reference implementation: [`4125fe7`](https://github.com/github/copilot-sdk/commit/4125fe7)) ### Changed -- **Protocol version bumped to v3.** The SDK now supports CLI servers running v2 or v3 (backward-compatible range). Sessions are now registered in the client's session map *before* the `session.create`/`session.resume` RPC is issued, ensuring broadcast events emitted immediately on session start are never dropped (upstream: [`4125fe7`](https://github.com/github/copilot-sdk/commit/4125fe7), [`1653812`](https://github.com/github/copilot-sdk/commit/1653812)) -- In protocol v3, tool calls and permission requests that have a registered handler are now handled automatically via `ExternalToolRequestedEvent` and `PermissionRequestedEvent` broadcast events; results are sent back via `session.tools.handlePendingToolCall` and `session.permissions.handlePendingPermissionRequest` RPC calls (upstream: [`1653812`](https://github.com/github/copilot-sdk/commit/1653812)) +- **Protocol version bumped to v3.** The SDK now supports CLI servers running v2 or v3 (backward-compatible range). Sessions are now registered in the client's session map *before* the `session.create`/`session.resume` RPC is issued, ensuring broadcast events emitted immediately on session start are never dropped (reference implementation: [`4125fe7`](https://github.com/github/copilot-sdk/commit/4125fe7), [`1653812`](https://github.com/github/copilot-sdk/commit/1653812)) +- In protocol v3, tool calls and permission requests that have a registered handler are now handled automatically via `ExternalToolRequestedEvent` and `PermissionRequestedEvent` broadcast events; results are sent back via `session.tools.handlePendingToolCall` and `session.permissions.handlePendingPermissionRequest` RPC calls (reference implementation: [`1653812`](https://github.com/github/copilot-sdk/commit/1653812)) ## [1.0.10] - 2026-03-03 -> **Upstream sync:** [`github/copilot-sdk@dcd86c1`](https://github.com/github/copilot-sdk/commit/dcd86c189501ce1b46b787ca60d90f3f315f3079) +> **Reference implementation sync:** [`github/copilot-sdk@dcd86c1`](https://github.com/github/copilot-sdk/commit/dcd86c189501ce1b46b787ca60d90f3f315f3079) ### Added -- `CopilotSession.setModel(String)` — changes the model for an existing session mid-conversation; the new model takes effect for the next message, and conversation history is preserved (upstream: [`bd98e3a`](https://github.com/github/copilot-sdk/commit/bd98e3a)) -- `ToolDefinition.createOverride(String, String, Map, ToolHandler)` — creates a tool definition that overrides a built-in CLI tool with the same name (upstream: [`f843c80`](https://github.com/github/copilot-sdk/commit/f843c80)) -- `ToolDefinition` record now includes `overridesBuiltInTool` field; when `true`, signals to the CLI that the custom tool intentionally replaces a built-in (upstream: [`f843c80`](https://github.com/github/copilot-sdk/commit/f843c80)) -- `CopilotSession.listAgents()` — lists custom agents available for selection (upstream: [`9d998fb`](https://github.com/github/copilot-sdk/commit/9d998fb)) -- `CopilotSession.getCurrentAgent()` — gets the currently selected custom agent (upstream: [`9d998fb`](https://github.com/github/copilot-sdk/commit/9d998fb)) -- `CopilotSession.selectAgent(String)` — selects a custom agent for the session (upstream: [`9d998fb`](https://github.com/github/copilot-sdk/commit/9d998fb)) -- `CopilotSession.deselectAgent()` — deselects the current custom agent (upstream: [`9d998fb`](https://github.com/github/copilot-sdk/commit/9d998fb)) -- `CopilotSession.compact()` — triggers immediate session context compaction (upstream: [`9d998fb`](https://github.com/github/copilot-sdk/commit/9d998fb)) -- `AgentInfo` — new JSON type representing a custom agent with `name`, `displayName`, and `description` (upstream: [`9d998fb`](https://github.com/github/copilot-sdk/commit/9d998fb)) -- New event types: `SessionTaskCompleteEvent` (`session.task_complete`), `AssistantStreamingDeltaEvent` (`assistant.streaming_delta`), `SubagentDeselectedEvent` (`subagent.deselected`) (upstream: various commits) +- `CopilotSession.setModel(String)` — changes the model for an existing session mid-conversation; the new model takes effect for the next message, and conversation history is preserved (reference implementation: [`bd98e3a`](https://github.com/github/copilot-sdk/commit/bd98e3a)) +- `ToolDefinition.createOverride(String, String, Map, ToolHandler)` — creates a tool definition that overrides a built-in CLI tool with the same name (reference implementation: [`f843c80`](https://github.com/github/copilot-sdk/commit/f843c80)) +- `ToolDefinition` record now includes `overridesBuiltInTool` field; when `true`, signals to the CLI that the custom tool intentionally replaces a built-in (reference implementation: [`f843c80`](https://github.com/github/copilot-sdk/commit/f843c80)) +- `CopilotSession.listAgents()` — lists custom agents available for selection (reference implementation: [`9d998fb`](https://github.com/github/copilot-sdk/commit/9d998fb)) +- `CopilotSession.getCurrentAgent()` — gets the currently selected custom agent (reference implementation: [`9d998fb`](https://github.com/github/copilot-sdk/commit/9d998fb)) +- `CopilotSession.selectAgent(String)` — selects a custom agent for the session (reference implementation: [`9d998fb`](https://github.com/github/copilot-sdk/commit/9d998fb)) +- `CopilotSession.deselectAgent()` — deselects the current custom agent (reference implementation: [`9d998fb`](https://github.com/github/copilot-sdk/commit/9d998fb)) +- `CopilotSession.compact()` — triggers immediate session context compaction (reference implementation: [`9d998fb`](https://github.com/github/copilot-sdk/commit/9d998fb)) +- `AgentInfo` — new JSON type representing a custom agent with `name`, `displayName`, and `description` (reference implementation: [`9d998fb`](https://github.com/github/copilot-sdk/commit/9d998fb)) +- New event types: `SessionTaskCompleteEvent` (`session.task_complete`), `AssistantStreamingDeltaEvent` (`assistant.streaming_delta`), `SubagentDeselectedEvent` (`subagent.deselected`) (reference implementation: various commits) - `AssistantTurnStartEvent` data now includes `interactionId` field - `AssistantMessageEvent` data now includes `interactionId` field - `ToolExecutionCompleteEvent` data now includes `model` and `interactionId` fields - `SkillInvokedEvent` data now includes `pluginName` and `pluginVersion` fields - `AssistantUsageEvent` data now includes `copilotUsage` field with `CopilotUsage` and `TokenDetails` nested types -- E2E tests for custom tool permission approval and denial flows (upstream: [`388f2f3`](https://github.com/github/copilot-sdk/commit/388f2f3)) +- E2E tests for custom tool permission approval and denial flows (reference implementation: [`388f2f3`](https://github.com/github/copilot-sdk/commit/388f2f3)) ### Changed -- **Breaking:** `createSession(SessionConfig)` now requires a non-null `onPermissionRequest` handler; throws `IllegalArgumentException` if not provided (upstream: [`279f6c4`](https://github.com/github/copilot-sdk/commit/279f6c4)) -- **Breaking:** `resumeSession(String, ResumeSessionConfig)` now requires a non-null `onPermissionRequest` handler; throws `IllegalArgumentException` if not provided (upstream: [`279f6c4`](https://github.com/github/copilot-sdk/commit/279f6c4)) -- **Breaking:** The no-arg `createSession()` and `resumeSession(String)` overloads were removed (upstream: [`279f6c4`](https://github.com/github/copilot-sdk/commit/279f6c4)) -- `AssistantMessageDeltaEvent` data: `totalResponseSizeBytes` field moved to new `AssistantStreamingDeltaEvent` (upstream: various) +- **Breaking:** `createSession(SessionConfig)` now requires a non-null `onPermissionRequest` handler; throws `IllegalArgumentException` if not provided (reference implementation: [`279f6c4`](https://github.com/github/copilot-sdk/commit/279f6c4)) +- **Breaking:** `resumeSession(String, ResumeSessionConfig)` now requires a non-null `onPermissionRequest` handler; throws `IllegalArgumentException` if not provided (reference implementation: [`279f6c4`](https://github.com/github/copilot-sdk/commit/279f6c4)) +- **Breaking:** The no-arg `createSession()` and `resumeSession(String)` overloads were removed (reference implementation: [`279f6c4`](https://github.com/github/copilot-sdk/commit/279f6c4)) +- `AssistantMessageDeltaEvent` data: `totalResponseSizeBytes` field moved to new `AssistantStreamingDeltaEvent` (reference implementation: various) ### Fixed -- Permission checks now also apply to SDK-registered custom tools, invoking the `onPermissionRequest` handler with `kind="custom-tool"` before executing tools (upstream: [`388f2f3`](https://github.com/github/copilot-sdk/commit/388f2f3)) +- Permission checks now also apply to SDK-registered custom tools, invoking the `onPermissionRequest` handler with `kind="custom-tool"` before executing tools (reference implementation: [`388f2f3`](https://github.com/github/copilot-sdk/commit/388f2f3)) ## [1.0.9] - 2026-02-16 -> **Upstream sync:** [`github/copilot-sdk@e40d57c`](https://github.com/github/copilot-sdk/commit/e40d57c86e18b495722adbf42045288c03924342) +> **Reference implementation sync:** [`github/copilot-sdk@e40d57c`](https://github.com/github/copilot-sdk/commit/e40d57c86e18b495722adbf42045288c03924342) ### Added #### Cookbook with Practical Recipes @@ -191,7 +191,7 @@ session.on(SessionContextChangedEvent.class, event -> { ## [1.0.8] - 2026-02-08 -> **Upstream sync:** [`github/copilot-sdk@05e3c46`](https://github.com/github/copilot-sdk/commit/05e3c46c8c23130c9c064dc43d00ec78f7a75eab) +> **Reference implementation sync:** [`github/copilot-sdk@05e3c46`](https://github.com/github/copilot-sdk/commit/05e3c46c8c23130c9c064dc43d00ec78f7a75eab) ### Added @@ -347,7 +347,7 @@ New types: `GetForegroundSessionResponse`, `SetForegroundSessionResponse` ### Changed - Enhanced permission request handling with graceful error recovery -- Updated test harness integration to clone from upstream SDK +- Updated test harness integration to clone from reference implementation SDK - Improved logging for session events and user input requests ### Fixed @@ -366,8 +366,8 @@ New types: `GetForegroundSessionResponse`, `SetForegroundSessionResponse` ### Changed -- Merged upstream SDK changes (commit 87ff5510) -- Added agentic-merge-upstream Claude skill for tracking upstream changes +- Merged reference implementation SDK changes (commit 87ff5510) +- Added agentic-merge-reference-impl Claude skill for tracking reference implementation changes ### Fixed @@ -376,7 +376,7 @@ New types: `GetForegroundSessionResponse`, `SetForegroundSessionResponse` - NPM dependency installation in CI workflow - Enhanced error handling in permission request processing - Checkstyle and Maven Resources Plugin version updates -- Test harness CLI installation to match upstream version +- Test harness CLI installation to match reference implementation version ## [1.0.4] - 2026-01-27 @@ -394,7 +394,7 @@ New types: `GetForegroundSessionResponse`, `SetForegroundSessionResponse` - Refactored tool argument handling for improved type safety - Optimized event listener registration in examples - Enhanced site navigation with documentation links -- Merged upstream SDK changes from commit f902b76 +- Merged reference implementation SDK changes from commit f902b76 ### Fixed @@ -410,7 +410,7 @@ New types: `GetForegroundSessionResponse`, `SetForegroundSessionResponse` - MCP Servers documentation and integration examples - Infinite sessions documentation section - Versioned documentation template with version selector -- Guidelines for porting upstream SDK changes to Java +- Guidelines for porting reference implementation SDK changes to Java - Configuration for automatically generated release notes ### Changed @@ -519,3 +519,4 @@ New types: `GetForegroundSessionResponse`, `SetForegroundSessionResponse` [1.0.2]: https://github.com/github/copilot-sdk-java/compare/v1.0.1...v1.0.2 [1.0.1]: https://github.com/github/copilot-sdk-java/compare/1.0.0...v1.0.1 [1.0.0]: https://github.com/github/copilot-sdk-java/releases/tag/1.0.0 + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6c85671bf..f86976c01 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,7 @@ Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. -This repository contains the **GitHub Copilot SDK for Java**, the official Java variant of the official [GitHub Copilot SDK](https://github.com/github/copilot-sdk). For issues or features related to the upstream SDK, please contribute there instead. +This repository contains the **GitHub Copilot SDK for Java**, the official Java variant of the official [GitHub Copilot SDK](https://github.com/github/copilot-sdk). For issues or features related to the reference implementation SDK, please contribute there instead. Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE). @@ -65,3 +65,4 @@ Here are a few things you can do that will increase the likelihood of your pull - [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) - [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) - [GitHub Help](https://help.github.com) + diff --git a/README.md b/README.md index 34c04ace7..d425fa4eb 100644 --- a/README.md +++ b/README.md @@ -153,7 +153,7 @@ jbang https://github.com/github/copilot-sdk-java/blob/latest/jbang-example.java ## CI/CD Workflows -This project uses several GitHub Actions workflows for building, testing, releasing, and syncing with the upstream SDK. +This project uses several GitHub Actions workflows for building, testing, releasing, and syncing with the reference implementation SDK. See [WORKFLOWS.md](docs/WORKFLOWS.md) for a full overview and details on each workflow. @@ -212,3 +212,4 @@ MIT — see [LICENSE](LICENSE) for details. [![Star History Chart](https://api.star-history.com/svg?repos=github/copilot-sdk-java&type=Date)](https://www.star-history.com/#github/copilot-sdk-java&Date) ⭐ Drop a star if you find this useful! + diff --git a/docs/WORKFLOWS.md b/docs/WORKFLOWS.md index 57ec34f71..1cbb22b36 100644 --- a/docs/WORKFLOWS.md +++ b/docs/WORKFLOWS.md @@ -21,9 +21,9 @@ Runs on every push to `main`, on pull requests, and in merge groups. Also runs w Steps: 1. Checks code formatting with Spotless -2. Compiles the SDK and clones the upstream test harness +2. Compiles the SDK and clones the reference implementation test harness 3. Verifies Javadoc generation -4. Installs the Copilot CLI from the cloned upstream SDK +4. Installs the Copilot CLI from the cloned reference implementation SDK 5. Runs the full test suite with `mvn verify` 6. Uploads test results (JaCoCo + Surefire) as artifacts for site generation @@ -98,3 +98,4 @@ Sets up: - JDK 17 (Temurin) - `gh-aw` CLI extension - Maven cache + diff --git a/docs/adr/adr-001-semver-pre-general-availability.md b/docs/adr/adr-001-semver-pre-general-availability.md index 44c9cf6db..33bdcc86c 100644 --- a/docs/adr/adr-001-semver-pre-general-availability.md +++ b/docs/adr/adr-001-semver-pre-general-availability.md @@ -20,8 +20,9 @@ We took an architectural decision to enable us to pursue investigating this poss Chosen option: "Track SemVer of reference implementation, with one exception.", because this enables us to pursue Virtual Threads without delaying the first public release of `copilot-sdk-java`. Also, we're supposed to be aggressively modernizing our customers. -To some extent, I would use qualifiers to mark a release as having some feature that is awaiting an upstream full release before it goes full ga, i.e you put out 0.1.46-virtualthreads.3 until upstream is ready to move to 0.2.0 then you release your virtual threads change and go 0.2.0. So I would make your agreement that your version numbers would match with the exception of qualifiers that you might add in exceptional circumstances. +To some extent, I would use qualifiers to mark a release as having some feature that is awaiting an reference implementation full release before it goes full ga, i.e you put out 0.1.46-virtualthreads.3 until reference implementation is ready to move to 0.2.0 then you release your virtual threads change and go 0.2.0. So I would make your agreement that your version numbers would match with the exception of qualifiers that you might add in exceptional circumstances. ## Related work items - https://devdiv.visualstudio.com/DevDiv/_workitems/edit/2745172 + diff --git a/docs/adr/adr-002-maven-version-and-reference-implementation-tracking.md b/docs/adr/adr-002-maven-version-and-reference-implementation-tracking.md index 7ef3d8ec8..6a0b54f22 100644 --- a/docs/adr/adr-002-maven-version-and-reference-implementation-tracking.md +++ b/docs/adr/adr-002-maven-version-and-reference-implementation-tracking.md @@ -6,7 +6,7 @@ Releases of this implementation track releases of the reference implementation. ## Considered Options -- Simple number qualifier (0.1.32-0, 0.1.32-1, ...) fails on a subtle but important point: 0.1.32-0 is treated identically to 0.1.32 by Maven (trailing zeros are normalized away), and bare numeric qualifiers are pre-release semantics. Your "first release" would sort before the upstream bare version. +- Simple number qualifier (0.1.32-0, 0.1.32-1, ...) fails on a subtle but important point: 0.1.32-0 is treated identically to 0.1.32 by Maven (trailing zeros are normalized away), and bare numeric qualifiers are pre-release semantics. Your "first release" would sort before the reference implementation bare version. - Java and number in the qualifier (0.1.32-java.N @@ -54,3 +54,4 @@ Everything looks healthy. Here's the status: ## Related work items - https://devdiv.visualstudio.com/DevDiv/_workitems/edit/2766089 + diff --git a/src/test/java/com/github/copilot/sdk/CommandsTest.java b/src/test/java/com/github/copilot/sdk/CommandsTest.java index baf26b39b..6bddbed28 100644 --- a/src/test/java/com/github/copilot/sdk/CommandsTest.java +++ b/src/test/java/com/github/copilot/sdk/CommandsTest.java @@ -25,7 +25,8 @@ * representation). * *

- * Ported from {@code CommandsTests.cs} in the upstream dotnet SDK. + * Ported from {@code CommandsTests.cs} in the reference implementation dotnet + * SDK. *

*/ class CommandsTest { diff --git a/src/test/java/com/github/copilot/sdk/ElicitationTest.java b/src/test/java/com/github/copilot/sdk/ElicitationTest.java index d6e2ac0b5..6b748b4cc 100644 --- a/src/test/java/com/github/copilot/sdk/ElicitationTest.java +++ b/src/test/java/com/github/copilot/sdk/ElicitationTest.java @@ -29,7 +29,8 @@ * Unit tests for the Elicitation feature and Session Capabilities. * *

- * Ported from {@code ElicitationTests.cs} in the upstream dotnet SDK. + * Ported from {@code ElicitationTests.cs} in the reference implementation + * dotnet SDK. *

*/ class ElicitationTest { diff --git a/src/test/java/com/github/copilot/sdk/HooksTest.java b/src/test/java/com/github/copilot/sdk/HooksTest.java index 05cd3292b..1278d082b 100644 --- a/src/test/java/com/github/copilot/sdk/HooksTest.java +++ b/src/test/java/com/github/copilot/sdk/HooksTest.java @@ -36,8 +36,8 @@ * *

* Note: Tests for userPromptSubmitted, sessionStart, and sessionEnd hooks are - * not included as they are not tested in the upstream .NET or Node.js SDKs and - * require test harness updates to properly invoke these hooks. + * not included as they are not tested in the reference implementation .NET or + * Node.js SDKs and require test harness updates to properly invoke these hooks. *

*/ public class HooksTest { From 406186b80d5ed1f5fef26e516a4caa1b1432fdfa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Apr 2026 19:26:14 +0000 Subject: [PATCH 72/80] Fix [reference-impl-hash] parameter naming in update-changelog.sh Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/dc42a537-067a-4251-bd14-0fb8fede94d9 Co-authored-by: edburns <75821+edburns@users.noreply.github.com> --- .github/scripts/release/update-changelog.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/scripts/release/update-changelog.sh b/.github/scripts/release/update-changelog.sh index 926da5b3b..ff35dec72 100755 --- a/.github/scripts/release/update-changelog.sh +++ b/.github/scripts/release/update-changelog.sh @@ -2,13 +2,13 @@ set -e # Script to update CHANGELOG.md during release process -# Usage: ./update-changelog.sh [reference implementation-hash] +# Usage: ./update-changelog.sh [reference-impl-hash] # Example: ./update-changelog.sh 1.0.8 # Example: ./update-changelog.sh 1.0.8 05e3c46c8c23130c9c064dc43d00ec78f7a75eab if [ -z "$1" ]; then echo "Error: Version argument required" - echo "Usage: $0 [reference implementation-hash]" + echo "Usage: $0 [reference-impl-hash]" exit 1 fi From e3f246a1cd7a79507dc7dc9e8cbc815fe81110dc Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Thu, 16 Apr 2026 18:15:55 -0400 Subject: [PATCH 73/80] Ignore tilde files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ddb2508ba..f079a3d20 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ changebundle.txt* .classpath .project .settings +*~ From df6a925db1e400dee2eae6cd63a5238590fe79fc Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Thu, 16 Apr 2026 18:26:33 -0400 Subject: [PATCH 74/80] Address very important comment by copilot. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @Copilot wrote: > This file is runtime-imported by weekly-reference-impl-sync.lock.yml as the agent prompt, but its content is written as documentation rather than imperative agent instructions (e.g., it doesn’t tell the agent to read .lastmerge, clone, compare commits, and must call a safe-output tool). As a result, the agentic workflow may fail or behave unpredictably. Please restore the prior imperative, step-by-step instruction style (like the deleted weekly-upstream-sync.md), updated to the new reference-impl terminology, and ensure it explicitly requires calling create-issue/close-issue/noop as appropriate. --- .../workflows/weekly-reference-impl-sync.md | 134 +++++++----------- 1 file changed, 50 insertions(+), 84 deletions(-) diff --git a/.github/workflows/weekly-reference-impl-sync.md b/.github/workflows/weekly-reference-impl-sync.md index 7e72248e1..711f16ccb 100644 --- a/.github/workflows/weekly-reference-impl-sync.md +++ b/.github/workflows/weekly-reference-impl-sync.md @@ -41,111 +41,77 @@ safe-outputs: noop: report-as-issue: false --- -# Weekly Reference Implementation Sync Agentic Workflow -This document describes the `weekly-reference-impl-sync.yml` GitHub Actions workflow, which automates the detection of new changes in the official [Copilot SDK](https://github.com/github/copilot-sdk) and delegates the merge work to the Copilot coding agent. +# Weekly Reference Implementation Sync -## Overview +You are an automation agent that detects new reference implementation changes and creates GitHub issues. You do **NOT** perform any code merges, edits, or pushes. Do **NOT** invoke any skills (especially `agentic-merge-reference-impl`). Your only job is to check for changes and use safe-output tools to create or close issues. -The workflow runs on a **weekly schedule** (every Monday at 10:00 UTC) and can also be triggered manually. It does **not** perform the actual merge — instead, it detects reference implementation changes and creates a GitHub issue assigned to `copilot`, instructing the agent to follow the [agentic-merge-reference-impl](../prompts/agentic-merge-reference-impl.prompt.md) prompt to port the changes. +## Instructions -The agent must also create the Pull Request with the label `reference-impl-sync`. This allows the workflow to track the merge progress and avoid creating duplicate issues if the agent is still working on a previous sync. +Follow these steps exactly: -## Trigger +### Step 1: Read `.lastmerge` -| Trigger | Schedule | -|---|---| -| `schedule` | Every Monday at 10:00 UTC (`0 10 * * 1`) | -| `workflow_dispatch` | Manual trigger from the Actions tab | +Read the file `.lastmerge` in the repository root. It contains the SHA of the last reference implementation commit that was merged into this Java SDK. -## Workflow Steps +### Step 2: Check for reference implementation changes -### 1. Checkout repository +Clone the reference implementation repository and compare commits: -Checks out the repo to read the `.lastmerge` file, which contains the SHA of the last reference implementation commit that was merged into the Java SDK. - -### 2. Check for reference implementation changes - -- Reads the last merged commit hash from `.lastmerge` -- Clones the reference implementation `github/copilot-sdk` repository -- Compares `.lastmerge` against reference implementation `HEAD` -- If they match: sets `has_changes=false` -- If they differ: counts new commits, generates a summary (up to 20 most recent), and sets outputs (`commit_count`, `reference_impl_head`, `last_merge`, `summary`) - -### 3. Close previous reference-impl-sync issues (when changes found) - -**Condition:** `has_changes == true` +```bash +LAST_MERGE=$(cat .lastmerge) +git clone --quiet https://github.com/github/copilot-sdk.git /tmp/gh-aw/agent/refererce-impl +cd /tmp/gh-aw/agent/refererce-impl +REFERENCE_IMPL_HEAD=$(git rev-parse HEAD) +``` -Before creating a new issue, closes any existing open issues with the `reference-impl-sync` label. This prevents stale issues from accumulating when previous sync attempts were incomplete or superseded. Each closed issue receives a comment explaining it was superseded. +If `LAST_MERGE` equals `REFERENCE_IMPL_HEAD`, there are **no new changes**. Go to Step 3a. -### 4. Close stale reference-impl-sync issues (when no changes found) +If they differ, count the new commits and generate a summary: -**Condition:** `has_changes == false` +```bash +COMMIT_COUNT=$(git rev-list --count "$LAST_MERGE".."$REFERENCE_IMPL_HEAD") +SUMMARY=$(git log --oneline "$LAST_MERGE".."$REFERENCE_IMPL_HEAD" | head -20) +``` -If the reference implementation is already up to date, closes any lingering open `reference-impl-sync` issues with a comment noting that no changes were detected. This handles the case where a previous issue was created but the changes were merged manually (updating `.lastmerge`) before the agent completed. +Go to Step 3b. -### 5. Create issue and assign to Copilot +### Step 3a: No changes detected -**Condition:** `has_changes == true` +1. Search for any open issues with the `reference-impl-sync` label using the GitHub MCP tools. +2. If there are open `reference-impl-sync` labeled issues, close each one using the `close_issue` safe-output tool with a comment: "No new reference implementation changes detected. The Java SDK is up to date. Closing." +3. Call the `noop` safe-output tool with message: "No new reference implementation changes since last merge ()." +4. **Stop here.** Do not proceed further. -Creates a new GitHub issue with: +### Step 3b: Changes detected -- **Title:** `Reference implementation sync: N new commits (YYYY-MM-DD)` -- **Label:** `reference-impl-sync` -- **Assignee:** `copilot` -- **Body:** Contains commit count, commit range links, a summary of recent commits, and a link to the merge prompt +1. Search for any open issues with the `refererce-impl-sync` label using the GitHub MCP tools. +2. Close each existing open `refererce-impl-sync` issue using the `close_issue` safe-output tool with a comment: "Superseded by a newer reference implementation sync check." +3. Create a new issue using the `create_issue` safe-output tool with: + - **Title:** `Reference Implementation sync: new commits ()` + - **Body:** Include the following information: + ``` + ## Automated Reference Implementation Sync -The Copilot coding agent picks up the issue, creates a branch and PR, then follows the merge prompt to port the changes. + There are **** new commits in the [official Copilot SDK](https://github.com/github/copilot-sdk) since the last merge. -### 6. Summary + - **Last merged commit:** [``](https://github.com/github/copilot-sdk/commit/) + - **Reference Implementation HEAD:** [``](https://github.com/github/copilot-sdk/commit/) -Writes a GitHub Actions step summary with: + ### Recent reference implementation commits -- Whether changes were detected -- Commit count and range -- Recent reference implementation commits -- Link to the created issue (if any) + ``` + + ``` -## Flow Diagram + ### Instructions -``` -┌─────────────────────┐ -│ Schedule / Manual │ -└──────────┬──────────┘ - │ - ▼ -┌──────────────────────────┐ -│ Read .lastmerge │ -│ Clone reference impl SDK │ -│ Compare commits │ -└──────────┬───────────────┘ - │ - ┌─────┴─────┐ - │ │ - changes? no changes - │ │ - ▼ ▼ -┌──────────┐ ┌──────────────────┐ -│ Close old│ │ Close stale │ -│ issues │ │ issues │ -└────┬─────┘ └──────────────────┘ - │ - ▼ -┌──────────────────────────┐ -│ Create issue assigned to │ -│ copilot │ -└──────────────────────────┘ - │ - ▼ -┌──────────────────────────┐ -│ Agent follows prompt to │ -│ port changes → PR │ -└──────────────────────────┘ -``` + Follow the [agentic-merge-reference-impl](.github/prompts/agentic-merge-reference-impl.prompt.md) prompt to port these changes to the Java SDK. + ``` +4. After creating the issue, use the `assign_to_agent` safe-output tool to assign Copilot to the newly created issue. -## Related Files +## Important constraints -| File | Purpose | -|---|---| -| `.lastmerge` | Stores the SHA of the last merged reference implementation commit | -| [agentic-merge-reference-impl.prompt.md](../prompts/agentic-merge-reference-impl.prompt.md) | Detailed instructions the Copilot agent follows to port changes | -| `.github/scripts/reference-impl-sync/` | Helper scripts used by the merge prompt | +- **Do NOT edit any files**, create branches, or push code. +- **Do NOT invoke any skills** such as `agentic-merge-agentic-merge-reference-impl` or `commit-as-pull-request`. +- **Do NOT attempt to merge or port reference implementation changes.** That is done by a separate agent that picks up the issue you create. +- You **MUST** call at least one safe-output tool (`create_issue`, `close_issue`, `noop`, etc.) before finishing. From 03cfc350f8cf23bdf918cf0a631dc2408f14153d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Apr 2026 23:02:30 +0000 Subject: [PATCH 75/80] Apply review suggestions: fix assignee, grammar, and refererce-impl typo Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/b635280e-2e95-4f3d-a5d9-a261f99c6e74 Co-authored-by: edburns <75821+edburns@users.noreply.github.com> --- .github/workflows/weekly-reference-impl-sync.md | 10 +++++----- docs/adr/adr-001-semver-pre-general-availability.md | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/weekly-reference-impl-sync.md b/.github/workflows/weekly-reference-impl-sync.md index 711f16ccb..1d1f9a4fd 100644 --- a/.github/workflows/weekly-reference-impl-sync.md +++ b/.github/workflows/weekly-reference-impl-sync.md @@ -24,7 +24,7 @@ tools: safe-outputs: create-issue: title-prefix: "[reference-impl-sync] " - assignees: [copilot] + assignees: [copilot-swe-agent] labels: [reference-impl-sync] expires: 6 close-issue: @@ -59,8 +59,8 @@ Clone the reference implementation repository and compare commits: ```bash LAST_MERGE=$(cat .lastmerge) -git clone --quiet https://github.com/github/copilot-sdk.git /tmp/gh-aw/agent/refererce-impl -cd /tmp/gh-aw/agent/refererce-impl +git clone --quiet https://github.com/github/copilot-sdk.git /tmp/gh-aw/agent/reference-impl +cd /tmp/gh-aw/agent/reference-impl REFERENCE_IMPL_HEAD=$(git rev-parse HEAD) ``` @@ -84,8 +84,8 @@ Go to Step 3b. ### Step 3b: Changes detected -1. Search for any open issues with the `refererce-impl-sync` label using the GitHub MCP tools. -2. Close each existing open `refererce-impl-sync` issue using the `close_issue` safe-output tool with a comment: "Superseded by a newer reference implementation sync check." +1. Search for any open issues with the `reference-impl-sync` label using the GitHub MCP tools. +2. Close each existing open `reference-impl-sync` issue using the `close_issue` safe-output tool with a comment: "Superseded by a newer reference implementation sync check." 3. Create a new issue using the `create_issue` safe-output tool with: - **Title:** `Reference Implementation sync: new commits ()` - **Body:** Include the following information: diff --git a/docs/adr/adr-001-semver-pre-general-availability.md b/docs/adr/adr-001-semver-pre-general-availability.md index 33bdcc86c..25008b0f5 100644 --- a/docs/adr/adr-001-semver-pre-general-availability.md +++ b/docs/adr/adr-001-semver-pre-general-availability.md @@ -20,7 +20,7 @@ We took an architectural decision to enable us to pursue investigating this poss Chosen option: "Track SemVer of reference implementation, with one exception.", because this enables us to pursue Virtual Threads without delaying the first public release of `copilot-sdk-java`. Also, we're supposed to be aggressively modernizing our customers. -To some extent, I would use qualifiers to mark a release as having some feature that is awaiting an reference implementation full release before it goes full ga, i.e you put out 0.1.46-virtualthreads.3 until reference implementation is ready to move to 0.2.0 then you release your virtual threads change and go 0.2.0. So I would make your agreement that your version numbers would match with the exception of qualifiers that you might add in exceptional circumstances. +To some extent, I would use qualifiers to mark a release as having some feature that is awaiting a reference implementation full release before it goes full ga, i.e you put out 0.1.46-virtualthreads.3 until reference implementation is ready to move to 0.2.0 then you release your virtual threads change and go 0.2.0. So I would make your agreement that your version numbers would match with the exception of qualifiers that you might add in exceptional circumstances. ## Related work items From 996d241a5ebf4cd01fe3b0ac73527f7f777a46ab Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Thu, 16 Apr 2026 22:55:30 -0400 Subject: [PATCH 76/80] Recompile agentic workflow lock file from updated .md source modified: .github/aw/actions-lock.json - Adds new pinned entry for `actions/github-script@v9` (sha `373c709c...`) - Updates `github/gh-aw-actions/setup` pin from `v0.63.1` to `v0.68.3` with new sha modified: .github/workflows/weekly-reference-impl-sync.lock.yml - Regenerated by `gh aw compile` (v0.68.3) from the `.md` source that was hand-edited in PR #77 without recompiling - Compiler upgraded from v0.51.6 to v0.68.3; schema version v1 to v3 - Frontmatter hash updated to reflect current `.md` content - `create_issue` assignee now correctly reflects `copilot-swe-agent` (was `copilot`) - `assign_to_agent` now includes `model: claude-opus-4.6` - Safe-outputs config updated with new tool entries (`create_report_incomplete_issue`, `report_incomplete`, `noop`) - Action pin references updated to match newer gh-aw-actions versions Signed-off-by: Ed Burns --- .github/aw/actions-lock.json | 11 +- .../weekly-reference-impl-sync.lock.yml | 1337 +++++++++-------- 2 files changed, 690 insertions(+), 658 deletions(-) diff --git a/.github/aw/actions-lock.json b/.github/aw/actions-lock.json index 0da84b9c6..1b8b4b56b 100644 --- a/.github/aw/actions-lock.json +++ b/.github/aw/actions-lock.json @@ -5,6 +5,11 @@ "version": "v8", "sha": "ed597411d8f924073f98dfc5c65a23a2325f34cd" }, + "actions/github-script@v9": { + "repo": "actions/github-script", + "version": "v9", + "sha": "373c709c69115d41ff229c7e5df9f8788daa9553" + }, "actions/setup-java@v4": { "repo": "actions/setup-java", "version": "v4", @@ -15,10 +20,10 @@ "version": "v4", "sha": "49933ea5288caeca8642d1e84afbd3f7d6820020" }, - "github/gh-aw-actions/setup@v0.63.1": { + "github/gh-aw-actions/setup@v0.68.3": { "repo": "github/gh-aw-actions/setup", - "version": "v0.63.1", - "sha": "53e09ec0be6271e81a69f51ef93f37212c8834b0" + "version": "v0.68.3", + "sha": "ba90f2186d7ad780ec640f364005fa24e797b360" }, "github/gh-aw/actions/setup@v0.51.6": { "repo": "github/gh-aw/actions/setup", diff --git a/.github/workflows/weekly-reference-impl-sync.lock.yml b/.github/workflows/weekly-reference-impl-sync.lock.yml index 25de1e1e8..49bfd3ac0 100644 --- a/.github/workflows/weekly-reference-impl-sync.lock.yml +++ b/.github/workflows/weekly-reference-impl-sync.lock.yml @@ -1,4 +1,5 @@ -# +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"54f733578d3011b148c7aff09a0e72085d787a777a996488f08aeffdf52ec93b","compiler_version":"v0.68.3","strict":true,"agent_id":"copilot"} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_AGENT_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"ba90f2186d7ad780ec640f364005fa24e797b360","version":"v0.68.3"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.20"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.20"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.19"},{"image":"ghcr.io/github/github-mcp-server:v0.32.0"},{"image":"node:lts-alpine"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -13,7 +14,7 @@ # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ # -# This file was automatically generated by gh-aw (v0.51.6). DO NOT EDIT. +# This file was automatically generated by gh-aw (v0.68.3). DO NOT EDIT. # # To update this file, edit the corresponding .md file and run: # gh aw compile @@ -24,88 +25,135 @@ # Weekly reference implementation sync workflow. Checks for new commits in the official # Copilot SDK (github/copilot-sdk) and assigns to Copilot to port changes. # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"fc14b09206c7aeafcd52c843adce996a1c14cf15875f9b647ef71f631b3b296e","compiler_version":"v0.51.6"} +# Secrets used: +# - COPILOT_GITHUB_TOKEN +# - GH_AW_AGENT_TOKEN +# - GH_AW_GITHUB_MCP_SERVER_TOKEN +# - GH_AW_GITHUB_TOKEN +# - GITHUB_TOKEN +# +# Custom actions used: +# - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 +# - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 +# - actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 +# - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 +# - github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3 +# +# Container images used: +# - ghcr.io/github/gh-aw-firewall/agent:0.25.20 +# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20 +# - ghcr.io/github/gh-aw-firewall/squid:0.25.20 +# - ghcr.io/github/gh-aw-mcpg:v0.2.19 +# - ghcr.io/github/github-mcp-server:v0.32.0 +# - node:lts-alpine -name: "Weekly Reference Implementation Sync Agentic Workflow" +name: "Weekly Reference Implementation Sync" "on": schedule: - - cron: "39 8 * * 2" + - cron: "40 11 * * 0" # Friendly format: weekly (scattered) workflow_dispatch: + inputs: + aw_context: + default: "" + description: Agent caller context (used internally by Agentic Workflows). + required: false + type: string permissions: {} concurrency: group: "gh-aw-${{ github.workflow }}" -run-name: "Weekly Reference Implementation Sync Agentic Workflow" +run-name: "Weekly Reference Implementation Sync" jobs: activation: runs-on: ubuntu-slim permissions: + actions: read contents: read outputs: comment_id: "" comment_repo: "" + lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} model: ${{ steps.generate_aw_info.outputs.model }} secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} + setup-trace-id: ${{ steps.setup.outputs.trace-id }} + stale_lock_file_failed: ${{ steps.check-lock-file.outputs.stale_lock_file_failed == 'true' }} steps: - name: Setup Scripts - uses: github/gh-aw/actions/setup@33cd6c7f1fee588654ef19def2e6a4174be66197 # v0.51.6 + id: setup + uses: github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3 with: - destination: /opt/gh-aw/actions + destination: ${{ runner.temp }}/gh-aw/actions + job-name: ${{ github.job }} - name: Generate agentic run info id: generate_aw_info env: GH_AW_INFO_ENGINE_ID: "copilot" GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" - GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} - GH_AW_INFO_VERSION: "" - GH_AW_INFO_AGENT_VERSION: "0.0.420" - GH_AW_INFO_CLI_VERSION: "v0.51.6" - GH_AW_INFO_WORKFLOW_NAME: "Weekly Reference Implementation Sync Agentic Workflow" + GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'auto' }} + GH_AW_INFO_VERSION: "1.0.21" + GH_AW_INFO_AGENT_VERSION: "1.0.21" + GH_AW_INFO_CLI_VERSION: "v0.68.3" + GH_AW_INFO_WORKFLOW_NAME: "Weekly Reference Implementation Sync" GH_AW_INFO_EXPERIMENTAL: "false" GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" GH_AW_INFO_STAGED: "false" GH_AW_INFO_ALLOWED_DOMAINS: '["defaults","github"]' GH_AW_INFO_FIREWALL_ENABLED: "true" - GH_AW_INFO_AWF_VERSION: "v0.23.0" + GH_AW_INFO_AWF_VERSION: "v0.25.20" GH_AW_INFO_AWMG_VERSION: "" GH_AW_INFO_FIREWALL_TYPE: "squid" - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + GH_AW_COMPILED_STRICT: "true" + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 with: script: | - const { main } = require('/opt/gh-aw/actions/generate_aw_info.cjs'); + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs'); await main(core, context); - name: Validate COPILOT_GITHUB_TOKEN secret id: validate-secret - run: /opt/gh-aw/actions/validate_multi_secret.sh COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default + run: bash "${RUNNER_TEMP}/gh-aw/actions/validate_multi_secret.sh" COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default env: COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - name: Checkout .github and .agents folders uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: + persist-credentials: false sparse-checkout: | .github .agents sparse-checkout-cone-mode: true fetch-depth: 1 - persist-credentials: false - - name: Check workflow file timestamps - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + - name: Check workflow lock file + id: check-lock-file + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 env: GH_AW_WORKFLOW_FILE: "weekly-reference-impl-sync.lock.yml" + GH_AW_CONTEXT_WORKFLOW_REF: "${{ github.workflow_ref }}" with: script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/check_workflow_timestamp_api.cjs'); + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/check_workflow_timestamp_api.cjs'); + await main(); + - name: Check compile-agentic version + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 + env: + GH_AW_COMPILED_VERSION: "v0.68.3" + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/check_version_updates.cjs'); await main(); - name: Create prompt with built-in context env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} + GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl GH_AW_GITHUB_ACTOR: ${{ github.actor }} GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} @@ -114,19 +162,20 @@ jobs: GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} + # poutine:ignore untrusted_checkout_exec run: | - bash /opt/gh-aw/actions/create_prompt_first.sh + bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_EOF' + cat << 'GH_AW_PROMPT_9a049ffd9b204d97_EOF' - GH_AW_PROMPT_EOF - cat "/opt/gh-aw/prompts/xpia.md" - cat "/opt/gh-aw/prompts/temp_folder_prompt.md" - cat "/opt/gh-aw/prompts/markdown.md" - cat "/opt/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_EOF' + GH_AW_PROMPT_9a049ffd9b204d97_EOF + cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" + cat << 'GH_AW_PROMPT_9a049ffd9b204d97_EOF' - Tools: add_comment, create_issue, close_issue, assign_to_agent, missing_tool, missing_data, noop + Tools: add_comment(max:10), create_issue, close_issue(max:10), assign_to_agent, missing_tool, missing_data, noop The following GitHub context information is available for this workflow: @@ -156,26 +205,25 @@ jobs: {{/if}} - GH_AW_PROMPT_EOF - cat << 'GH_AW_PROMPT_EOF' + GH_AW_PROMPT_9a049ffd9b204d97_EOF + cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" + cat << 'GH_AW_PROMPT_9a049ffd9b204d97_EOF' - GH_AW_PROMPT_EOF - cat << 'GH_AW_PROMPT_EOF' {{#runtime-import .github/workflows/weekly-reference-impl-sync.md}} - GH_AW_PROMPT_EOF + GH_AW_PROMPT_9a049ffd9b204d97_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt with: script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/interpolate_prompt.cjs'); + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/interpolate_prompt.cjs'); await main(); - name: Substitute placeholders - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_GITHUB_ACTOR: ${{ github.actor }} @@ -188,10 +236,10 @@ jobs: GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} with: script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); - const substitutePlaceholders = require('/opt/gh-aw/actions/substitute_placeholders.cjs'); + const substitutePlaceholders = require('${{ runner.temp }}/gh-aw/actions/substitute_placeholders.cjs'); // Call the substitution function return await substitutePlaceholders({ @@ -210,19 +258,23 @@ jobs: - name: Validate prompt placeholders env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - run: bash /opt/gh-aw/actions/validate_prompt_placeholders.sh + # poutine:ignore untrusted_checkout_exec + run: bash "${RUNNER_TEMP}/gh-aw/actions/validate_prompt_placeholders.sh" - name: Print prompt env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - run: bash /opt/gh-aw/actions/print_prompt_summary.sh + # poutine:ignore untrusted_checkout_exec + run: bash "${RUNNER_TEMP}/gh-aw/actions/print_prompt_summary.sh" - name: Upload activation artifact if: success() - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: activation path: | /tmp/gh-aw/aw_info.json /tmp/gh-aw/aw-prompts/prompt.txt + /tmp/gh-aw/github_rate_limits.jsonl + if-no-files-found: ignore retention-days: 1 agent: @@ -240,425 +292,292 @@ jobs: GH_AW_ASSETS_BRANCH: "" GH_AW_ASSETS_MAX_SIZE_KB: 0 GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs - GH_AW_SAFE_OUTPUTS: /opt/gh-aw/safeoutputs/outputs.jsonl - GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json - GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json GH_AW_WORKFLOW_ID_SANITIZED: weeklyreferenceimplsync outputs: + agentic_engine_timeout: ${{ steps.detect-copilot-errors.outputs.agentic_engine_timeout || 'false' }} checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} - detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }} - detection_success: ${{ steps.detection_conclusion.outputs.success }} + effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }} has_patch: ${{ steps.collect_output.outputs.has_patch }} + inference_access_error: ${{ steps.detect-copilot-errors.outputs.inference_access_error || 'false' }} + mcp_policy_error: ${{ steps.detect-copilot-errors.outputs.mcp_policy_error || 'false' }} model: ${{ needs.activation.outputs.model }} + model_not_supported_error: ${{ steps.detect-copilot-errors.outputs.model_not_supported_error || 'false' }} output: ${{ steps.collect_output.outputs.output }} output_types: ${{ steps.collect_output.outputs.output_types }} + setup-trace-id: ${{ steps.setup.outputs.trace-id }} steps: - name: Setup Scripts - uses: github/gh-aw/actions/setup@33cd6c7f1fee588654ef19def2e6a4174be66197 # v0.51.6 + id: setup + uses: github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3 with: - destination: /opt/gh-aw/actions + destination: ${{ runner.temp }}/gh-aw/actions + job-name: ${{ github.job }} + trace-id: ${{ needs.activation.outputs.setup-trace-id }} + - name: Set runtime paths + id: set-runtime-paths + run: | + { + echo "GH_AW_SAFE_OUTPUTS=${RUNNER_TEMP}/gh-aw/safeoutputs/outputs.jsonl" + echo "GH_AW_SAFE_OUTPUTS_CONFIG_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" + echo "GH_AW_SAFE_OUTPUTS_TOOLS_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/tools.json" + } >> "$GITHUB_OUTPUT" - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Create gh-aw temp directory - run: bash /opt/gh-aw/actions/create_gh_aw_tmp_dir.sh + run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh" + - name: Configure gh CLI for GitHub Enterprise + run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh" + env: + GH_TOKEN: ${{ github.token }} - name: Configure Git credentials env: REPO_NAME: ${{ github.repository }} SERVER_URL: ${{ github.server_url }} + GITHUB_TOKEN: ${{ github.token }} run: | git config --global user.email "github-actions[bot]@users.noreply.github.com" git config --global user.name "github-actions[bot]" git config --global am.keepcr true # Re-authenticate git with GitHub token SERVER_URL_STRIPPED="${SERVER_URL#https://}" - git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" echo "Git configured with standard GitHub Actions identity" - name: Checkout PR branch id: checkout-pr if: | - (github.event.pull_request) || (github.event.issue.pull_request) - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + github.event.pull_request || github.event.issue.pull_request + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 env: GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} with: github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/checkout_pr_branch.cjs'); + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs'); await main(); - name: Install GitHub Copilot CLI - run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.420 - - name: Install awf binary - run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.23.0 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.21 + env: + GH_HOST: github.com + - name: Install AWF binary + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.20 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 env: GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} with: script: | - const determineAutomaticLockdown = require('/opt/gh-aw/actions/determine_automatic_lockdown.cjs'); + const determineAutomaticLockdown = require('${{ runner.temp }}/gh-aw/actions/determine_automatic_lockdown.cjs'); await determineAutomaticLockdown(github, context, core); - name: Download container images - run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.6 ghcr.io/github/github-mcp-server:v0.31.0 node:lts-alpine + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.20 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20 ghcr.io/github/gh-aw-firewall/squid:0.25.20 ghcr.io/github/gh-aw-mcpg:v0.2.19 ghcr.io/github/github-mcp-server:v0.32.0 node:lts-alpine - name: Write Safe Outputs Config run: | - mkdir -p /opt/gh-aw/safeoutputs + mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF' - {"add_comment":{"max":10,"target":"*"},"assign_to_agent":{"default_agent":"copilot","max":1,"target":"*"},"close_issue":{"max":10,"required_labels":["reference-impl-sync"],"target":"*"},"create_issue":{"expires":144,"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1}} - GH_AW_SAFE_OUTPUTS_CONFIG_EOF - cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF' - [ - { - "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 1 issue(s) can be created. Title will be prefixed with \"[reference-impl-sync] \". Labels [reference-impl-sync] will be automatically added. Assignees [copilot] will be automatically assigned.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "body": { - "description": "Detailed issue description in Markdown. Do NOT repeat the title as a heading since it already appears as the issue's h1. Include context, reproduction steps, or acceptance criteria as appropriate.", - "type": "string" - }, - "labels": { - "description": "Labels to categorize the issue (e.g., 'bug', 'enhancement'). Labels must exist in the repository.", - "items": { - "type": "string" - }, - "type": "array" - }, - "parent": { - "description": "Parent issue number for creating sub-issues. This is the numeric ID from the GitHub URL (e.g., 42 in github.com/owner/repo/issues/42). Can also be a temporary_id (e.g., 'aw_abc123', 'aw_Test123') from a previously created issue in the same workflow run.", - "type": [ - "number", - "string" - ] - }, - "temporary_id": { - "description": "Unique temporary identifier for referencing this issue before it's created. Format: 'aw_' followed by 3 to 8 alphanumeric characters (e.g., 'aw_abc1', 'aw_Test123'). Use '#aw_ID' in body text to reference other issues by their temporary_id; these are replaced with actual issue numbers after creation.", - "pattern": "^aw_[A-Za-z0-9]{3,8}$", - "type": "string" - }, - "title": { - "description": "Concise issue title summarizing the bug, feature, or task. The title appears as the main heading, so keep it brief and descriptive.", - "type": "string" - } - }, - "required": [ - "title", - "body" - ], - "type": "object" - }, - "name": "create_issue" - }, + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_2a317c5680ea1925_EOF' + {"add_comment":{"max":10,"target":"*"},"assign_to_agent":{"max":1,"model":"claude-opus-4.6","name":"copilot","target":"*"},"close_issue":{"max":10,"required_labels":["reference-impl-sync"],"target":"*"},"create_issue":{"assignees":["copilot-swe-agent"],"expires":144,"labels":["reference-impl-sync"],"max":1,"title_prefix":"[reference-impl-sync] "},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"false"},"report_incomplete":{}} + GH_AW_SAFE_OUTPUTS_CONFIG_2a317c5680ea1925_EOF + - name: Write Safe Outputs Tools + env: + GH_AW_TOOLS_META_JSON: | { - "description": "Close a GitHub issue with a closing comment. You can and should always add a comment when closing an issue to explain the action or provide context. This tool is ONLY for closing issues - use update_issue if you need to change the title, body, labels, or other metadata without closing. Use close_issue when work is complete, the issue is no longer relevant, or it's a duplicate. The closing comment should explain the resolution or reason for closing. If the issue is already closed, a comment will still be posted. CONSTRAINTS: Maximum 10 issue(s) can be closed. Target: *.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "body": { - "description": "Closing comment explaining why the issue is being closed and summarizing any resolution, workaround, or conclusion.", - "type": "string" - }, - "issue_number": { - "description": "Issue number to close. This is the numeric ID from the GitHub URL (e.g., 901 in github.com/owner/repo/issues/901). If omitted, closes the issue that triggered this workflow (requires an issue event trigger).", - "type": [ - "number", - "string" - ] - } - }, - "required": [ - "body" - ], - "type": "object" + "description_suffixes": { + "add_comment": " CONSTRAINTS: Maximum 10 comment(s) can be added. Target: *. Supports reply_to_id for discussion threading.", + "assign_to_agent": " CONSTRAINTS: Maximum 1 issue(s) can be assigned to agent.", + "close_issue": " CONSTRAINTS: Maximum 10 issue(s) can be closed. Target: *.", + "create_issue": " CONSTRAINTS: Maximum 1 issue(s) can be created. Title will be prefixed with \"[reference-impl-sync] \". Labels [\"reference-impl-sync\"] will be automatically added. Assignees [\"copilot-swe-agent\"] will be automatically assigned." }, - "name": "close_issue" - }, + "repo_params": {}, + "dynamic_tools": [] + } + GH_AW_VALIDATION_JSON: | { - "description": "Add a comment to an existing GitHub issue, pull request, or discussion. Use this to provide feedback, answer questions, or add information to an existing conversation. For creating new items, use create_issue, create_discussion, or create_pull_request instead. IMPORTANT: Comments are subject to validation constraints enforced by the MCP server - maximum 65536 characters for the complete comment (including footer which is added automatically), 10 mentions (@username), and 50 links. Exceeding these limits will result in an immediate error with specific guidance. NOTE: By default, this tool requires discussions:write permission. If your GitHub App lacks Discussions permission, set 'discussions: false' in the workflow's safe-outputs.add-comment configuration to exclude this permission. CONSTRAINTS: Maximum 10 comment(s) can be added. Target: *.", - "inputSchema": { - "additionalProperties": false, - "properties": { + "add_comment": { + "defaultMax": 1, + "fields": { "body": { - "description": "The comment text in Markdown format. This is the 'body' field - do not use 'comment_body' or other variations. Provide helpful, relevant information that adds value to the conversation. CONSTRAINTS: The complete comment (your body text + automatically added footer) must not exceed 65536 characters total. Maximum 10 mentions (@username), maximum 50 links (http/https URLs). A footer (~200-500 characters) is automatically appended with workflow attribution, so leave adequate space. If these limits are exceeded, the tool call will fail with a detailed error message indicating which constraint was violated.", - "type": "string" + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 }, "item_number": { - "description": "The issue, pull request, or discussion number to comment on. This is the numeric ID from the GitHub URL (e.g., 123 in github.com/owner/repo/issues/123). If omitted, the tool auto-targets the issue, PR, or discussion that triggered this workflow. Auto-targeting only works for issue, pull_request, discussion, and comment event triggers — it does NOT work for schedule, workflow_dispatch, push, or workflow_run triggers. For those trigger types, always provide item_number explicitly, or the comment will be silently discarded.", - "type": "number" + "issueOrPRNumber": true + }, + "reply_to_id": { + "type": "string", + "maxLength": 256 + }, + "repo": { + "type": "string", + "maxLength": 256 } - }, - "required": [ - "body" - ], - "type": "object" + } }, - "name": "add_comment" - }, - { - "description": "Assign the GitHub Copilot coding agent to work on an issue or pull request. The agent will analyze the issue/PR and attempt to implement a solution, creating a pull request when complete. Use this to delegate coding tasks to Copilot. Example usage: assign_to_agent(issue_number=123, agent=\"copilot\") or assign_to_agent(pull_number=456, agent=\"copilot\", pull_request_repo=\"owner/repo\") CONSTRAINTS: Maximum 1 issue(s) can be assigned to agent.", - "inputSchema": { - "additionalProperties": false, - "properties": { + "assign_to_agent": { + "defaultMax": 1, + "fields": { "agent": { - "description": "Agent identifier to assign. Defaults to 'copilot' (the Copilot coding agent) if not specified.", - "type": "string" + "type": "string", + "sanitize": true, + "maxLength": 128 }, "issue_number": { - "description": "Issue number to assign the Copilot coding agent to. This is the numeric ID from the GitHub URL (e.g., 234 in github.com/owner/repo/issues/234). Can also be a temporary_id (e.g., 'aw_abc123', 'aw_Test123') from an issue created earlier in the same workflow run. The issue should contain clear, actionable requirements. Either issue_number or pull_number must be provided, but not both.", - "type": [ - "number", - "string" - ] + "issueNumberOrTemporaryId": true }, "pull_number": { - "description": "Pull request number to assign the Copilot coding agent to. This is the numeric ID from the GitHub URL (e.g., 456 in github.com/owner/repo/pull/456). Either issue_number or pull_number must be provided, but not both.", - "type": [ - "number", - "string" - ] + "optionalPositiveInteger": true }, "pull_request_repo": { - "description": "Target repository where the pull request should be created, in 'owner/repo' format. If omitted, the PR will be created in the same repository as the issue. This allows issues and code to live in different repositories. The global pull-request-repo configuration (if set) is automatically allowed; additional repositories must be listed in allowed-pull-request-repos.", - "type": "string" + "type": "string", + "maxLength": 256 + }, + "repo": { + "type": "string", + "maxLength": 256 } }, - "type": "object" + "customValidation": "requiresOneOf:issue_number,pull_number" }, - "name": "assign_to_agent" - }, - { - "description": "Report that a tool or capability needed to complete the task is not available, or share any information you deem important about missing functionality or limitations. Use this when you cannot accomplish what was requested because the required functionality is missing or access is restricted.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "alternatives": { - "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).", - "type": "string" + "close_issue": { + "defaultMax": 1, + "fields": { + "body": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 }, - "reason": { - "description": "Explanation of why this tool is needed or what information you want to share about the limitation (max 256 characters).", - "type": "string" + "issue_number": { + "optionalPositiveInteger": true }, - "tool": { - "description": "Optional: Name or description of the missing tool or capability (max 128 characters). Be specific about what functionality is needed.", - "type": "string" + "repo": { + "type": "string", + "maxLength": 256 } - }, - "required": [ - "reason" - ], - "type": "object" + } }, - "name": "missing_tool" - }, - { - "description": "Log a transparency message when no significant actions are needed. Use this to confirm workflow completion and provide visibility when analysis is complete but no changes or outputs are required (e.g., 'No issues found', 'All checks passed'). This ensures the workflow produces human-visible output even when no other actions are taken.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "message": { - "description": "Status or completion message to log. Should explain what was analyzed and the outcome (e.g., 'Code review complete - no issues found', 'Analysis complete - all tests passing').", + "create_issue": { + "defaultMax": 1, + "fields": { + "body": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "labels": { + "type": "array", + "itemType": "string", + "itemSanitize": true, + "itemMaxLength": 128 + }, + "parent": { + "issueOrPRNumber": true + }, + "repo": { + "type": "string", + "maxLength": 256 + }, + "temporary_id": { "type": "string" + }, + "title": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 128 } - }, - "required": [ - "message" - ], - "type": "object" + } }, - "name": "noop" - }, - { - "description": "Report that data or information needed to complete the task is not available. Use this when you cannot accomplish what was requested because required data, context, or information is missing.", - "inputSchema": { - "additionalProperties": false, - "properties": { + "missing_data": { + "defaultMax": 20, + "fields": { "alternatives": { - "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).", - "type": "string" + "type": "string", + "sanitize": true, + "maxLength": 256 }, "context": { - "description": "Additional context about the missing data or where it should come from (max 256 characters).", - "type": "string" + "type": "string", + "sanitize": true, + "maxLength": 256 }, "data_type": { - "description": "Type or description of the missing data or information (max 128 characters). Be specific about what data is needed.", - "type": "string" + "type": "string", + "sanitize": true, + "maxLength": 128 }, "reason": { - "description": "Explanation of why this data is needed to complete the task (max 256 characters).", - "type": "string" + "type": "string", + "sanitize": true, + "maxLength": 256 } - }, - "required": [], - "type": "object" - }, - "name": "missing_data" - } - ] - GH_AW_SAFE_OUTPUTS_TOOLS_EOF - cat > /opt/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_EOF' - { - "add_comment": { - "defaultMax": 1, - "fields": { - "body": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65000 - }, - "item_number": { - "issueOrPRNumber": true - }, - "repo": { - "type": "string", - "maxLength": 256 - } - } - }, - "assign_to_agent": { - "defaultMax": 1, - "fields": { - "agent": { - "type": "string", - "sanitize": true, - "maxLength": 128 - }, - "issue_number": { - "issueNumberOrTemporaryId": true - }, - "pull_number": { - "optionalPositiveInteger": true - }, - "pull_request_repo": { - "type": "string", - "maxLength": 256 - }, - "repo": { - "type": "string", - "maxLength": 256 } }, - "customValidation": "requiresOneOf:issue_number,pull_number" - }, - "close_issue": { - "defaultMax": 1, - "fields": { - "body": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65000 - }, - "issue_number": { - "optionalPositiveInteger": true - }, - "repo": { - "type": "string", - "maxLength": 256 - } - } - }, - "create_issue": { - "defaultMax": 1, - "fields": { - "body": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65000 - }, - "labels": { - "type": "array", - "itemType": "string", - "itemSanitize": true, - "itemMaxLength": 128 - }, - "parent": { - "issueOrPRNumber": true - }, - "repo": { - "type": "string", - "maxLength": 256 - }, - "temporary_id": { - "type": "string" - }, - "title": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 128 - } - } - }, - "missing_data": { - "defaultMax": 20, - "fields": { - "alternatives": { - "type": "string", - "sanitize": true, - "maxLength": 256 - }, - "context": { - "type": "string", - "sanitize": true, - "maxLength": 256 - }, - "data_type": { - "type": "string", - "sanitize": true, - "maxLength": 128 - }, - "reason": { - "type": "string", - "sanitize": true, - "maxLength": 256 + "missing_tool": { + "defaultMax": 20, + "fields": { + "alternatives": { + "type": "string", + "sanitize": true, + "maxLength": 512 + }, + "reason": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "tool": { + "type": "string", + "sanitize": true, + "maxLength": 128 + } } - } - }, - "missing_tool": { - "defaultMax": 20, - "fields": { - "alternatives": { - "type": "string", - "sanitize": true, - "maxLength": 512 - }, - "reason": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 256 - }, - "tool": { - "type": "string", - "sanitize": true, - "maxLength": 128 + }, + "noop": { + "defaultMax": 1, + "fields": { + "message": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + } } - } - }, - "noop": { - "defaultMax": 1, - "fields": { - "message": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65000 + }, + "report_incomplete": { + "defaultMax": 5, + "fields": { + "details": { + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "reason": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 1024 + } } } } - } - GH_AW_SAFE_OUTPUTS_VALIDATION_EOF + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_safe_outputs_tools.cjs'); + await main(); - name: Generate Safe Outputs MCP Server Config id: safe-outputs-config run: | @@ -681,29 +600,32 @@ jobs: id: safe-outputs-start env: DEBUG: '*' + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }} GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }} - GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json - GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json + GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/tools.json + GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/config.json GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs run: | # Environment variables are set above to prevent template injection export DEBUG + export GH_AW_SAFE_OUTPUTS export GH_AW_SAFE_OUTPUTS_PORT export GH_AW_SAFE_OUTPUTS_API_KEY export GH_AW_SAFE_OUTPUTS_TOOLS_PATH export GH_AW_SAFE_OUTPUTS_CONFIG_PATH export GH_AW_MCP_LOG_DIR - bash /opt/gh-aw/actions/start_safe_outputs_server.sh + bash "${RUNNER_TEMP}/gh-aw/actions/start_safe_outputs_server.sh" - name: Start MCP Gateway id: start-mcp-gateway env: - GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }} GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }} - GITHUB_MCP_LOCKDOWN: ${{ steps.determine-automatic-lockdown.outputs.lockdown == 'true' && '1' || '0' }} + GITHUB_MCP_GUARD_MIN_INTEGRITY: ${{ steps.determine-automatic-lockdown.outputs.min_integrity }} + GITHUB_MCP_GUARD_REPOS: ${{ steps.determine-automatic-lockdown.outputs.repos }} GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} run: | set -eo pipefail @@ -721,20 +643,26 @@ jobs: export DEBUG="*" export GH_AW_ENGINE="copilot" - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_LOCKDOWN -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.1.6' + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.2.19' mkdir -p /home/runner/.copilot - cat << GH_AW_MCP_CONFIG_EOF | bash /opt/gh-aw/actions/start_mcp_gateway.sh + cat << GH_AW_MCP_CONFIG_ee30822602a32ffa_EOF | bash "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh" { "mcpServers": { "github": { "type": "stdio", - "container": "ghcr.io/github/github-mcp-server:v0.31.0", + "container": "ghcr.io/github/github-mcp-server:v0.32.0", "env": { - "GITHUB_LOCKDOWN_MODE": "$GITHUB_MCP_LOCKDOWN", + "GITHUB_HOST": "\${GITHUB_SERVER_URL}", "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", "GITHUB_READ_ONLY": "1", "GITHUB_TOOLSETS": "context,repos,issues" + }, + "guard-policies": { + "allow-only": { + "min-integrity": "$GITHUB_MCP_GUARD_MIN_INTEGRITY", + "repos": "$GITHUB_MCP_GUARD_REPOS" + } } }, "safeoutputs": { @@ -742,6 +670,13 @@ jobs: "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT", "headers": { "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}" + }, + "guard-policies": { + "write-sink": { + "accept": [ + "*" + ] + } } } }, @@ -752,67 +687,70 @@ jobs: "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" } } - GH_AW_MCP_CONFIG_EOF + GH_AW_MCP_CONFIG_ee30822602a32ffa_EOF - name: Download activation artifact - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: activation path: /tmp/gh-aw - name: Clean git credentials - run: bash /opt/gh-aw/actions/clean_git_credentials.sh + continue-on-error: true + run: bash "${RUNNER_TEMP}/gh-aw/actions/clean_git_credentials.sh" - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): timeout-minutes: 20 run: | set -o pipefail + touch /tmp/gh-aw/agent-step-summary.md + (umask 177 && touch /tmp/gh-aw/agent-stdio.log) # shellcheck disable=SC1003 - sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \ - -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"}' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --allow-domains '*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.20 --skip-pull --enable-api-proxy \ + -- /bin/bash -c 'node ${RUNNER_TEMP}/gh-aw/actions/copilot_driver.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json - GH_AW_MODEL_AGENT_COPILOT: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} + GH_AW_PHASE: agent GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} + GH_AW_VERSION: v0.68.3 GITHUB_API_URL: ${{ github.api_url }} + GITHUB_AW: true GITHUB_HEAD_REF: ${{ github.head_ref }} GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} GITHUB_REF_NAME: ${{ github.ref_name }} GITHUB_SERVER_URL: ${{ github.server_url }} - GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} + GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md GITHUB_WORKSPACE: ${{ github.workspace }} + GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_AUTHOR_NAME: github-actions[bot] + GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_COMMITTER_NAME: github-actions[bot] XDG_CONFIG_HOME: /home/runner + - name: Detect Copilot errors + id: detect-copilot-errors + if: always() + continue-on-error: true + run: node "${RUNNER_TEMP}/gh-aw/actions/detect_copilot_errors.cjs" - name: Configure Git credentials env: REPO_NAME: ${{ github.repository }} SERVER_URL: ${{ github.server_url }} + GITHUB_TOKEN: ${{ github.token }} run: | git config --global user.email "github-actions[bot]@users.noreply.github.com" git config --global user.name "github-actions[bot]" git config --global am.keepcr true # Re-authenticate git with GitHub token SERVER_URL_STRIPPED="${SERVER_URL#https://}" - git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" echo "Git configured with standard GitHub Actions identity" - name: Copy Copilot session state files to logs if: always() continue-on-error: true - run: | - # Copy Copilot session state files to logs folder for artifact collection - # This ensures they are in /tmp/gh-aw/ where secret redaction can scan them - SESSION_STATE_DIR="$HOME/.copilot/session-state" - LOGS_DIR="/tmp/gh-aw/sandbox/agent/logs" - - if [ -d "$SESSION_STATE_DIR" ]; then - echo "Copying Copilot session state files from $SESSION_STATE_DIR to $LOGS_DIR" - mkdir -p "$LOGS_DIR" - cp -v "$SESSION_STATE_DIR"/*.jsonl "$LOGS_DIR/" 2>/dev/null || true - echo "Session state files copied successfully" - else - echo "No session-state directory found at $SESSION_STATE_DIR" - fi + run: bash "${RUNNER_TEMP}/gh-aw/actions/copy_copilot_session_state.sh" - name: Stop MCP Gateway if: always() continue-on-error: true @@ -821,15 +759,15 @@ jobs: MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }} GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }} run: | - bash /opt/gh-aw/actions/stop_mcp_gateway.sh "$GATEWAY_PID" + bash "${RUNNER_TEMP}/gh-aw/actions/stop_mcp_gateway.sh" "$GATEWAY_PID" - name: Redact secrets in logs if: always() - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 with: script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/redact_secrets.cjs'); + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/redact_secrets.cjs'); await main(); env: GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' @@ -837,62 +775,51 @@ jobs: SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Upload Safe Outputs + - name: Append agent step summary if: always() - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 - with: - name: safe-output - path: ${{ env.GH_AW_SAFE_OUTPUTS }} - if-no-files-found: warn + run: bash "${RUNNER_TEMP}/gh-aw/actions/append_agent_step_summary.sh" + - name: Copy Safe Outputs + if: always() + env: + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} + run: | + mkdir -p /tmp/gh-aw + cp "$GH_AW_SAFE_OUTPUTS" /tmp/gh-aw/safeoutputs.jsonl 2>/dev/null || true - name: Ingest agent output id: collect_output if: always() - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 env: - GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} with: script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/collect_ndjson_output.cjs'); + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/collect_ndjson_output.cjs'); await main(); - - name: Upload sanitized agent output - if: always() && env.GH_AW_AGENT_OUTPUT - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 - with: - name: agent-output - path: ${{ env.GH_AW_AGENT_OUTPUT }} - if-no-files-found: warn - - name: Upload engine output files - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 - with: - name: agent_outputs - path: | - /tmp/gh-aw/sandbox/agent/logs/ - /tmp/gh-aw/redacted-urls.log - if-no-files-found: ignore - name: Parse agent logs for step summary if: always() - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 env: GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/ with: script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/parse_copilot_log.cjs'); + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_copilot_log.cjs'); await main(); - name: Parse MCP Gateway logs for step summary if: always() - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + id: parse-mcp-gateway + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 with: script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/parse_mcp_gateway_log.cjs'); + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_mcp_gateway_log.cjs'); await main(); - name: Print firewall logs if: always() @@ -909,26 +836,236 @@ jobs: else echo 'AWF binary not installed, skipping firewall log summary' fi + - name: Parse token usage for step summary + if: always() + continue-on-error: true + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_token_usage.cjs'); + await main(); + - name: Write agent output placeholder if missing + if: always() + run: | + if [ ! -f /tmp/gh-aw/agent_output.json ]; then + echo '{"items":[]}' > /tmp/gh-aw/agent_output.json + fi - name: Upload agent artifacts if: always() continue-on-error: true - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: agent-artifacts + name: agent path: | /tmp/gh-aw/aw-prompts/prompt.txt + /tmp/gh-aw/sandbox/agent/logs/ + /tmp/gh-aw/redacted-urls.log /tmp/gh-aw/mcp-logs/ - /tmp/gh-aw/sandbox/firewall/logs/ + /tmp/gh-aw/agent_usage.json /tmp/gh-aw/agent-stdio.log /tmp/gh-aw/agent/ + /tmp/gh-aw/github_rate_limits.jsonl + /tmp/gh-aw/safeoutputs.jsonl + /tmp/gh-aw/agent_output.json + /tmp/gh-aw/aw-*.patch + /tmp/gh-aw/aw-*.bundle + /tmp/gh-aw/sandbox/firewall/logs/ + /tmp/gh-aw/sandbox/firewall/audit/ if-no-files-found: ignore - # --- Threat Detection (inline) --- + + conclusion: + needs: + - activation + - agent + - detection + - safe_outputs + if: > + always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true' || + needs.activation.outputs.stale_lock_file_failed == 'true') + runs-on: ubuntu-slim + permissions: + contents: read + discussions: write + issues: write + pull-requests: write + concurrency: + group: "gh-aw-conclusion-weekly-reference-impl-sync" + cancel-in-progress: false + outputs: + incomplete_count: ${{ steps.report_incomplete.outputs.incomplete_count }} + noop_message: ${{ steps.noop.outputs.noop_message }} + tools_reported: ${{ steps.missing_tool.outputs.tools_reported }} + total_count: ${{ steps.missing_tool.outputs.total_count }} + steps: + - name: Setup Scripts + id: setup + uses: github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3 + with: + destination: ${{ runner.temp }}/gh-aw/actions + job-name: ${{ github.job }} + trace-id: ${{ needs.activation.outputs.setup-trace-id }} + - name: Download agent output artifact + id: download-agent-output + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: agent + path: /tmp/gh-aw/ + - name: Setup agent output environment variable + id: setup-agent-output-env + if: steps.download-agent-output.outcome == 'success' + run: | + mkdir -p /tmp/gh-aw/ + find "/tmp/gh-aw/" -type f -print + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + - name: Process no-op messages + id: noop + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_NOOP_MAX: "1" + GH_AW_WORKFLOW_NAME: "Weekly Reference Implementation Sync" + GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} + GH_AW_NOOP_REPORT_AS_ISSUE: "false" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_noop_message.cjs'); + await main(); + - name: Log detection run + id: detection_runs + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Weekly Reference Implementation Sync" + GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }} + GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }} + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_detection_runs.cjs'); + await main(); + - name: Record missing tool + id: missing_tool + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_MISSING_TOOL_CREATE_ISSUE: "true" + GH_AW_WORKFLOW_NAME: "Weekly Reference Implementation Sync" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/missing_tool.cjs'); + await main(); + - name: Record incomplete + id: report_incomplete + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true" + GH_AW_WORKFLOW_NAME: "Weekly Reference Implementation Sync" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/report_incomplete_handler.cjs'); + await main(); + - name: Handle agent failure + id: handle_agent_failure + if: always() + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Weekly Reference Implementation Sync" + GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} + GH_AW_WORKFLOW_ID: "weekly-reference-impl-sync" + GH_AW_ENGINE_ID: "copilot" + GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} + GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} + GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }} + GH_AW_MCP_POLICY_ERROR: ${{ needs.agent.outputs.mcp_policy_error }} + GH_AW_AGENTIC_ENGINE_TIMEOUT: ${{ needs.agent.outputs.agentic_engine_timeout }} + GH_AW_MODEL_NOT_SUPPORTED_ERROR: ${{ needs.agent.outputs.model_not_supported_error }} + GH_AW_ASSIGNMENT_ERRORS: ${{ needs.safe_outputs.outputs.assign_to_agent_assignment_errors }} + GH_AW_ASSIGNMENT_ERROR_COUNT: ${{ needs.safe_outputs.outputs.assign_to_agent_assignment_error_count }} + GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }} + GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }} + GH_AW_GROUP_REPORTS: "false" + GH_AW_FAILURE_REPORT_AS_ISSUE: "true" + GH_AW_TIMEOUT_MINUTES: "20" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs'); + await main(); + + detection: + needs: + - activation + - agent + if: > + always() && needs.agent.result != 'skipped' && (needs.agent.outputs.output_types != '' || needs.agent.outputs.has_patch == 'true') + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }} + detection_reason: ${{ steps.detection_conclusion.outputs.reason }} + detection_success: ${{ steps.detection_conclusion.outputs.success }} + steps: + - name: Setup Scripts + id: setup + uses: github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3 + with: + destination: ${{ runner.temp }}/gh-aw/actions + job-name: ${{ github.job }} + trace-id: ${{ needs.activation.outputs.setup-trace-id }} + - name: Download agent output artifact + id: download-agent-output + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: agent + path: /tmp/gh-aw/ + - name: Setup agent output environment variable + id: setup-agent-output-env + if: steps.download-agent-output.outcome == 'success' + run: | + mkdir -p /tmp/gh-aw/ + find "/tmp/gh-aw/" -type f -print + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + - name: Checkout repository for patch context + if: needs.agent.outputs.has_patch == 'true' + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + # --- Threat Detection --- + - name: Clean stale firewall files from agent artifact + run: | + rm -rf /tmp/gh-aw/sandbox/firewall/logs + rm -rf /tmp/gh-aw/sandbox/firewall/audit + - name: Download container images + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.20 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20 ghcr.io/github/gh-aw-firewall/squid:0.25.20 - name: Check if detection needed id: detection_guard if: always() env: - OUTPUT_TYPES: ${{ steps.collect_output.outputs.output_types }} - HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }} + OUTPUT_TYPES: ${{ needs.agent.outputs.output_types }} + HAS_PATCH: ${{ needs.agent.outputs.has_patch }} run: | if [[ -n "$OUTPUT_TYPES" || "$HAS_PATCH" == "true" ]]; then echo "run_detection=true" >> "$GITHUB_OUTPUT" @@ -952,194 +1089,93 @@ jobs: for f in /tmp/gh-aw/aw-*.patch; do [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true done + for f in /tmp/gh-aw/aw-*.bundle; do + [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true + done echo "Prepared threat detection files:" ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true - name: Setup threat detection if: always() && steps.detection_guard.outputs.run_detection == 'true' - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 env: - WORKFLOW_NAME: "Weekly Reference Implementation Sync Agentic Workflow" + WORKFLOW_NAME: "Weekly Reference Implementation Sync" WORKFLOW_DESCRIPTION: "Weekly reference implementation sync workflow. Checks for new commits in the official\nCopilot SDK (github/copilot-sdk) and assigns to Copilot to port changes." - HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }} + HAS_PATCH: ${{ needs.agent.outputs.has_patch }} with: script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/setup_threat_detection.cjs'); + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/setup_threat_detection.cjs'); await main(); - name: Ensure threat-detection directory and log if: always() && steps.detection_guard.outputs.run_detection == 'true' run: | mkdir -p /tmp/gh-aw/threat-detection touch /tmp/gh-aw/threat-detection/detection.log + - name: Install GitHub Copilot CLI + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.21 + env: + GH_HOST: github.com + - name: Install AWF binary + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.20 - name: Execute GitHub Copilot CLI if: always() && steps.detection_guard.outputs.run_detection == 'true' id: detection_agentic_execution # Copilot CLI tool arguments (sorted): - # --allow-tool shell(cat) - # --allow-tool shell(grep) - # --allow-tool shell(head) - # --allow-tool shell(jq) - # --allow-tool shell(ls) - # --allow-tool shell(tail) - # --allow-tool shell(wc) timeout-minutes: 20 run: | set -o pipefail + touch /tmp/gh-aw/agent-step-summary.md + (umask 177 && touch /tmp/gh-aw/threat-detection/detection.log) # shellcheck disable=SC1003 - sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,raw.githubusercontent.com,registry.npmjs.org,telemetry.enterprise.githubcopilot.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \ - -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(wc)'\'' --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_DETECTION_COPILOT:+ --model "$GH_AW_MODEL_DETECTION_COPILOT"}' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,telemetry.enterprise.githubcopilot.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.20 --skip-pull --enable-api-proxy \ + -- /bin/bash -c 'node ${RUNNER_TEMP}/gh-aw/actions/copilot_driver.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - GH_AW_MODEL_DETECTION_COPILOT: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }} + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }} + GH_AW_PHASE: detection GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_VERSION: v0.68.3 GITHUB_API_URL: ${{ github.api_url }} + GITHUB_AW: true GITHUB_HEAD_REF: ${{ github.head_ref }} GITHUB_REF_NAME: ${{ github.ref_name }} GITHUB_SERVER_URL: ${{ github.server_url }} - GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} + GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md GITHUB_WORKSPACE: ${{ github.workspace }} + GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_AUTHOR_NAME: github-actions[bot] + GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_COMMITTER_NAME: github-actions[bot] XDG_CONFIG_HOME: /home/runner - - name: Parse threat detection results - id: parse_detection_results - if: always() && steps.detection_guard.outputs.run_detection == 'true' - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/parse_threat_detection_results.cjs'); - await main(); - name: Upload threat detection log if: always() && steps.detection_guard.outputs.run_detection == 'true' - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: threat-detection.log + name: detection path: /tmp/gh-aw/threat-detection/detection.log if-no-files-found: ignore - - name: Set detection conclusion + - name: Parse and conclude threat detection id: detection_conclusion if: always() + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 env: RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }} - DETECTION_SUCCESS: ${{ steps.parse_detection_results.outputs.success }} - run: | - if [[ "$RUN_DETECTION" != "true" ]]; then - echo "conclusion=skipped" >> "$GITHUB_OUTPUT" - echo "success=true" >> "$GITHUB_OUTPUT" - echo "Detection was not needed, marking as skipped" - elif [[ "$DETECTION_SUCCESS" == "true" ]]; then - echo "conclusion=success" >> "$GITHUB_OUTPUT" - echo "success=true" >> "$GITHUB_OUTPUT" - echo "Detection passed successfully" - else - echo "conclusion=failure" >> "$GITHUB_OUTPUT" - echo "success=false" >> "$GITHUB_OUTPUT" - echo "Detection found issues" - fi - - conclusion: - needs: - - activation - - agent - - safe_outputs - if: (always()) && (needs.agent.result != 'skipped') - runs-on: ubuntu-slim - permissions: - contents: read - discussions: write - issues: write - pull-requests: write - outputs: - noop_message: ${{ steps.noop.outputs.noop_message }} - tools_reported: ${{ steps.missing_tool.outputs.tools_reported }} - total_count: ${{ steps.missing_tool.outputs.total_count }} - steps: - - name: Setup Scripts - uses: github/gh-aw/actions/setup@33cd6c7f1fee588654ef19def2e6a4174be66197 # v0.51.6 - with: - destination: /opt/gh-aw/actions - - name: Download agent output artifact - continue-on-error: true - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 - with: - name: agent-output - path: /tmp/gh-aw/safeoutputs/ - - name: Setup agent output environment variable - run: | - mkdir -p /tmp/gh-aw/safeoutputs/ - find "/tmp/gh-aw/safeoutputs/" -type f -print - echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" - - name: Process No-Op Messages - id: noop - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_NOOP_MAX: "1" - GH_AW_WORKFLOW_NAME: "Weekly Reference Implementation Sync Agentic Workflow" + GH_AW_DETECTION_CONTINUE_ON_ERROR: "true" with: - github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/noop.cjs'); - await main(); - - name: Record Missing Tool - id: missing_tool - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_WORKFLOW_NAME: "Weekly Reference Implementation Sync Agentic Workflow" - with: - github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/missing_tool.cjs'); - await main(); - - name: Handle Agent Failure - id: handle_agent_failure - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_WORKFLOW_NAME: "Weekly Reference Implementation Sync Agentic Workflow" - GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} - GH_AW_WORKFLOW_ID: "weekly-reference-impl-sync" - GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} - GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} - GH_AW_ASSIGNMENT_ERRORS: ${{ needs.safe_outputs.outputs.assign_to_agent_assignment_errors }} - GH_AW_ASSIGNMENT_ERROR_COUNT: ${{ needs.safe_outputs.outputs.assign_to_agent_assignment_error_count }} - GH_AW_GROUP_REPORTS: "false" - with: - github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/handle_agent_failure.cjs'); - await main(); - - name: Handle No-Op Message - id: handle_noop_message - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_WORKFLOW_NAME: "Weekly Reference Implementation Sync Agentic Workflow" - GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} - GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }} - GH_AW_NOOP_REPORT_AS_ISSUE: "false" - with: - github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/handle_noop_message.cjs'); + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_threat_detection_results.cjs'); await main(); safe_outputs: - needs: agent - if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.agent.outputs.detection_success == 'true') + needs: + - activation + - agent + - detection + if: (!cancelled()) && needs.agent.result != 'skipped' && needs.detection.result == 'success' runs-on: ubuntu-slim permissions: contents: read @@ -1148,14 +1184,18 @@ jobs: pull-requests: write timeout-minutes: 15 env: - GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/${{ github.workflow }}" + GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/weekly-reference-impl-sync" + GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }} + GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }} + GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }} GH_AW_ENGINE_ID: "copilot" + GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }} GH_AW_WORKFLOW_ID: "weekly-reference-impl-sync" - GH_AW_WORKFLOW_NAME: "Weekly Reference Implementation Sync Agentic Workflow" + GH_AW_WORKFLOW_NAME: "Weekly Reference Implementation Sync" outputs: - assign_to_agent_assigned: ${{ steps.assign_to_agent.outputs.assigned }} - assign_to_agent_assignment_error_count: ${{ steps.assign_to_agent.outputs.assignment_error_count }} - assign_to_agent_assignment_errors: ${{ steps.assign_to_agent.outputs.assignment_errors }} + assign_to_agent_assigned: ${{ steps.process_safe_outputs.outputs.assign_to_agent_assigned }} + assign_to_agent_assignment_error_count: ${{ steps.process_safe_outputs.outputs.assign_to_agent_assignment_error_count }} + assign_to_agent_assignment_errors: ${{ steps.process_safe_outputs.outputs.assign_to_agent_assignment_errors }} code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }} code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }} comment_id: ${{ steps.process_safe_outputs.outputs.comment_id }} @@ -1168,72 +1208,59 @@ jobs: process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} steps: - name: Setup Scripts - uses: github/gh-aw/actions/setup@33cd6c7f1fee588654ef19def2e6a4174be66197 # v0.51.6 + id: setup + uses: github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3 with: - destination: /opt/gh-aw/actions + destination: ${{ runner.temp }}/gh-aw/actions + job-name: ${{ github.job }} + trace-id: ${{ needs.activation.outputs.setup-trace-id }} - name: Download agent output artifact + id: download-agent-output continue-on-error: true - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: agent-output - path: /tmp/gh-aw/safeoutputs/ + name: agent + path: /tmp/gh-aw/ - name: Setup agent output environment variable + id: setup-agent-output-env + if: steps.download-agent-output.outcome == 'success' + run: | + mkdir -p /tmp/gh-aw/ + find "/tmp/gh-aw/" -type f -print + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + - name: Configure GH_HOST for enterprise compatibility + id: ghes-host-config + shell: bash run: | - mkdir -p /tmp/gh-aw/safeoutputs/ - find "/tmp/gh-aw/safeoutputs/" -type f -print - echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct + # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op. + GH_HOST="${GITHUB_SERVER_URL#https://}" + GH_HOST="${GH_HOST#http://}" + echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV" - name: Process Safe Outputs id: process_safe_outputs - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":10,\"target\":\"*\"},\"close_issue\":{\"max\":10,\"required_labels\":[\"reference-impl-sync\"],\"target\":\"*\"},\"create_issue\":{\"assignees\":[\"copilot\"],\"expires\":144,\"labels\":[\"reference-impl-sync\"],\"max\":1,\"title_prefix\":\"[reference-impl-sync] \"},\"missing_data\":{},\"missing_tool\":{}}" - GH_AW_ASSIGN_COPILOT: "true" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":10,\"target\":\"*\"},\"assign_to_agent\":{\"max\":1,\"model\":\"claude-opus-4.6\",\"name\":\"copilot\",\"target\":\"*\"},\"close_issue\":{\"max\":10,\"required_labels\":[\"reference-impl-sync\"],\"target\":\"*\"},\"create_issue\":{\"assignees\":[\"copilot-swe-agent\"],\"expires\":144,\"labels\":[\"reference-impl-sync\"],\"max\":1,\"title_prefix\":\"[reference-impl-sync] \"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"false\"},\"report_incomplete\":{}}" + GH_AW_ASSIGN_TO_AGENT_TOKEN: ${{ secrets.GH_AW_AGENT_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/safe_output_handler_manager.cjs'); + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/safe_output_handler_manager.cjs'); await main(); - - name: Assign Copilot to created issues - if: steps.process_safe_outputs.outputs.issues_to_assign_copilot != '' - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_ISSUES_TO_ASSIGN_COPILOT: ${{ steps.process_safe_outputs.outputs.issues_to_assign_copilot }} - with: - github-token: ${{ secrets.GH_AW_AGENT_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/assign_copilot_to_created_issues.cjs'); - await main(); - - name: Assign to agent - id: assign_to_agent - if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'assign_to_agent')) - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_AGENT_MAX_COUNT: 1 - GH_AW_AGENT_DEFAULT: "copilot" - GH_AW_AGENT_DEFAULT_MODEL: "claude-opus-4.6" - GH_AW_AGENT_TARGET: "*" - GH_AW_TEMPORARY_ID_MAP: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} - with: - github-token: ${{ secrets.GH_AW_AGENT_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/assign_to_agent.cjs'); - await main(); - - name: Upload safe output items manifest + - name: Upload Safe Outputs Items if: always() - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: safe-output-items - path: /tmp/safe-output-items.jsonl - if-no-files-found: warn + name: safe-outputs-items + path: | + /tmp/gh-aw/safe-output-items.jsonl + /tmp/gh-aw/temporary-id-map.json + if-no-files-found: ignore From f7c41b87f4df38c444ee7adf4f6ea08c07135806 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Fri, 17 Apr 2026 13:24:29 -0400 Subject: [PATCH 77/80] Add classical code generation workflow for typed event and RPC classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces a TypeScript-based code generator (scripts/codegen/java.ts) that reads api.schema.json and session-events.schema.json to produce: - Typed session event classes (sealed hierarchy under AbstractSessionEvent) - Typed RPC wrapper classes (ServerRpc, SessionRpc) for JSON-RPC methods - Jackson-annotated records with @JsonCreator, @JsonProperty, @JsonInclude Migrates the hand-written events package to auto-generated types, wires the generated RPC wrappers into CopilotClient and CopilotSession, and adds comprehensive tests including E2E coverage. Also includes: Windows CLI path resolution fixes, shared TestUtil extraction, lazy getRpc() initialization, race condition fix in SessionEventsE2ETest, and a guard preventing agentic sync from modifying src/generated/java/ files. Fix review comments: getRpc() IllegalStateException, UnknownSessionEvent wire type, anyOf heuristic, remove unused var Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/9b8b782c-22ad-450f-885d-2b11d5808a0c Co-authored-by: edburns <75821+edburns@users.noreply.github.com> Revert "Fix review comments: getRpc() IllegalStateException, UnknownSessionEvent wire type, anyOf heuristic, remove unused var" This reverts commit ef1de834e6c54daca56ecb326263841087995fe0. Fix Big Risk 1. `sendExpandedToolResult()` bypasses the typed wrapper (HIGH) scripts/codegen/java.ts - Remove the special-case `anyOf` rule that picked `String` when exactly 2 non-null branches included a string type. Multi-branch `anyOf` now falls through to `Object`, matching the C# reference generator's behavior. src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsHandlePendingToolCallParams.java - Change the `result` field type from `String` to `Object` (regenerated output reflecting the `anyOf` rule fix in `java.ts`). src/main/java/com/github/copilot/sdk/CopilotSession.java - Replace the `sendExpandedToolResult(requestId, toolResult)` call with a direct typed-wrapper call: `getRpc().tools.handlePendingToolCall(new SessionToolsHandlePendingToolCallParams(...))`. - Delete the `sendExpandedToolResult()` private method and its Javadoc block, which are no longer needed now that the `result` field accepts `Object`. Signed-off-by: Ed Burns On branch copilot/add-classical-code-gen-workflow-ready-for-review modified: scripts/codegen/java.ts - Put `visible = true` on `SessionEventEvent`. - Add `type` property. on `UnknownSessionEvent`. modified: src/generated/java/com/github/copilot/sdk/generated/SessionEvent.java modified: src/generated/java/com/github/copilot/sdk/generated/UnknownSessionEvent.java - Regenerated. modified: src/main/java/com/github/copilot/sdk/CopilotSession.java - Use Double Check Locked to fix Big Risk #2 2. Lazy `SessionRpc` initialization is not thread-safe (HIGH) modified: src/test/java/com/github/copilot/sdk/ForwardCompatibilityTest.java modified: src/test/java/com/github/copilot/sdk/SessionEventDeserializationTest.java - Refine tests based on changes. Signed-off-by: Ed Burns On branch copilot/add-classical-code-gen-workflow-ready-for-review modified: pom.xml - Add profiles for generating code and updating the schemas from which the code is generated. modified: scripts/codegen/java.ts - Address copilot comment: > requiredSet is computed but never used in renderNestedType(), which makes the generator harder to maintain (and can confuse future changes around nullability/boxing). Remove it or use it to drive required-vs-optional component typing if that’s the intent. Signed-off-by: Ed Burns Add AI code review to update-copilot-dependency workflow --- .gitattributes | 3 +- .github/copilot-instructions.md | 2 +- .../agentic-merge-reference-impl.prompt.md | 45 +- ...agent-merge-reference-impl-instructions.md | 14 + .github/workflows/codegen-check.yml | 44 + .../workflows/update-copilot-dependency.yml | 144 ++ .gitignore | 3 +- README.md | 4 +- config/checkstyle/checkstyle.xml | 4 +- config/spotbugs/spotbugs-exclude.xml | 4 +- docs/WORKFLOWS.md | 38 + jbang-example.java | 4 +- pom.xml | 121 ++ scripts/codegen/.gitignore | 1 + scripts/codegen/java.ts | 1322 +++++++++++++++++ scripts/codegen/package-lock.json | 645 ++++++++ scripts/codegen/package.json | 14 + .../copilot/sdk/generated/AbortEvent.java | 42 + .../sdk/generated/AssistantIntentEvent.java | 42 + .../generated/AssistantMessageDeltaEvent.java | 46 + .../sdk/generated/AssistantMessageEvent.java | 104 ++ .../AssistantReasoningDeltaEvent.java | 44 + .../generated/AssistantReasoningEvent.java | 44 + .../AssistantStreamingDeltaEvent.java | 42 + .../sdk/generated/AssistantTurnEndEvent.java | 42 + .../generated/AssistantTurnStartEvent.java | 44 + .../sdk/generated/AssistantUsageEvent.java | 125 ++ .../generated/CapabilitiesChangedEvent.java | 51 + .../sdk/generated/CommandCompletedEvent.java | 42 + .../sdk/generated/CommandExecuteEvent.java | 48 + .../sdk/generated/CommandQueuedEvent.java | 44 + .../sdk/generated/CommandsChangedEvent.java | 51 + .../generated/ElicitationCompletedEvent.java | 69 + .../generated/ElicitationRequestedEvent.java | 89 ++ .../generated/ExitPlanModeCompletedEvent.java | 50 + .../generated/ExitPlanModeRequestedEvent.java | 51 + .../generated/ExternalToolCompletedEvent.java | 42 + .../generated/ExternalToolRequestedEvent.java | 54 + .../copilot/sdk/generated/HookEndEvent.java | 61 + .../copilot/sdk/generated/HookStartEvent.java | 46 + .../sdk/generated/McpOauthCompletedEvent.java | 42 + .../sdk/generated/McpOauthRequiredEvent.java | 59 + .../PendingMessagesModifiedEvent.java | 39 + .../generated/PermissionCompletedEvent.java | 81 + .../generated/PermissionRequestedEvent.java | 46 + .../sdk/generated/SamplingCompletedEvent.java | 42 + .../sdk/generated/SamplingRequestedEvent.java | 46 + .../SessionBackgroundTasksChangedEvent.java | 39 + .../SessionCompactionCompleteEvent.java | 83 ++ .../SessionCompactionStartEvent.java | 46 + .../generated/SessionContextChangedEvent.java | 74 + .../SessionCustomAgentsUpdatedEvent.java | 69 + .../sdk/generated/SessionErrorEvent.java | 52 + .../copilot/sdk/generated/SessionEvent.java | 215 +++ .../SessionExtensionsLoadedEvent.java | 101 ++ .../sdk/generated/SessionHandoffEvent.java | 88 ++ .../sdk/generated/SessionIdleEvent.java | 42 + .../sdk/generated/SessionInfoEvent.java | 46 + .../SessionMcpServerStatusChangedEvent.java | 72 + .../SessionMcpServersLoadedEvent.java | 85 ++ .../generated/SessionModeChangedEvent.java | 44 + .../generated/SessionModelChangeEvent.java | 48 + .../generated/SessionPlanChangedEvent.java | 64 + .../SessionRemoteSteerableChangedEvent.java | 42 + .../sdk/generated/SessionResumeEvent.java | 96 ++ .../sdk/generated/SessionShutdownEvent.java | 137 ++ .../generated/SessionSkillsLoadedEvent.java | 61 + .../generated/SessionSnapshotRewindEvent.java | 44 + .../sdk/generated/SessionStartEvent.java | 102 ++ .../generated/SessionTaskCompleteEvent.java | 44 + .../generated/SessionTitleChangedEvent.java | 42 + .../generated/SessionToolsUpdatedEvent.java | 41 + .../sdk/generated/SessionTruncationEvent.java | 56 + .../sdk/generated/SessionUsageInfoEvent.java | 54 + .../sdk/generated/SessionWarningEvent.java | 46 + .../SessionWorkspaceFileChangedEvent.java | 64 + .../sdk/generated/SkillInvokedEvent.java | 55 + .../sdk/generated/SubagentCompletedEvent.java | 54 + .../generated/SubagentDeselectedEvent.java | 39 + .../sdk/generated/SubagentFailedEvent.java | 56 + .../sdk/generated/SubagentSelectedEvent.java | 47 + .../sdk/generated/SubagentStartedEvent.java | 48 + .../sdk/generated/SystemMessageEvent.java | 80 + .../generated/SystemNotificationEvent.java | 44 + .../generated/ToolExecutionCompleteEvent.java | 84 ++ .../ToolExecutionPartialResultEvent.java | 44 + .../generated/ToolExecutionProgressEvent.java | 44 + .../generated/ToolExecutionStartEvent.java | 52 + .../sdk/generated/ToolUserRequestedEvent.java | 46 + .../sdk/generated/UnknownSessionEvent.java | 31 + .../generated/UserInputCompletedEvent.java | 46 + .../generated/UserInputRequestedEvent.java | 51 + .../sdk/generated/UserMessageEvent.java | 77 + .../generated/rpc/AccountGetQuotaResult.java | 46 + .../sdk/generated/rpc/McpConfigAddParams.java | 29 + .../generated/rpc/McpConfigListResult.java | 28 + .../generated/rpc/McpConfigRemoveParams.java | 27 + .../generated/rpc/McpConfigUpdateParams.java | 29 + .../sdk/generated/rpc/McpDiscoverParams.java | 27 + .../sdk/generated/rpc/McpDiscoverResult.java | 66 + .../sdk/generated/rpc/ModelsListResult.java | 118 ++ .../copilot/sdk/generated/rpc/PingParams.java | 27 + .../copilot/sdk/generated/rpc/PingResult.java | 31 + .../copilot/sdk/generated/rpc/RpcCaller.java | 39 + .../copilot/sdk/generated/rpc/RpcMapper.java | 28 + .../sdk/generated/rpc/ServerAccountApi.java | 36 + .../sdk/generated/rpc/ServerMcpApi.java | 40 + .../sdk/generated/rpc/ServerMcpConfigApi.java | 60 + .../sdk/generated/rpc/ServerModelsApi.java | 36 + .../copilot/sdk/generated/rpc/ServerRpc.java | 63 + .../sdk/generated/rpc/ServerSessionFsApi.java | 36 + .../sdk/generated/rpc/ServerSessionsApi.java | 38 + .../sdk/generated/rpc/ServerToolsApi.java | 36 + .../sdk/generated/rpc/SessionAgentApi.java | 84 ++ .../rpc/SessionAgentDeselectParams.java | 27 + .../rpc/SessionAgentDeselectResult.java | 24 + .../rpc/SessionAgentGetCurrentParams.java | 27 + .../rpc/SessionAgentGetCurrentResult.java | 39 + .../generated/rpc/SessionAgentListParams.java | 27 + .../generated/rpc/SessionAgentListResult.java | 40 + .../rpc/SessionAgentReloadParams.java | 27 + .../rpc/SessionAgentReloadResult.java | 40 + .../rpc/SessionAgentSelectParams.java | 29 + .../rpc/SessionAgentSelectResult.java | 40 + .../sdk/generated/rpc/SessionCommandsApi.java | 42 + ...ionCommandsHandlePendingCommandParams.java | 31 + ...ionCommandsHandlePendingCommandResult.java | 27 + .../generated/rpc/SessionExtensionsApi.java | 76 + .../rpc/SessionExtensionsDisableParams.java | 29 + .../rpc/SessionExtensionsDisableResult.java | 24 + .../rpc/SessionExtensionsEnableParams.java | 29 + .../rpc/SessionExtensionsEnableResult.java | 24 + .../rpc/SessionExtensionsListParams.java | 27 + .../rpc/SessionExtensionsListResult.java | 88 ++ .../rpc/SessionExtensionsReloadParams.java | 27 + .../rpc/SessionExtensionsReloadResult.java | 24 + .../sdk/generated/rpc/SessionFleetApi.java | 44 + .../rpc/SessionFleetStartParams.java | 29 + .../rpc/SessionFleetStartResult.java | 27 + .../rpc/SessionFsAppendFileParams.java | 33 + .../generated/rpc/SessionFsExistsParams.java | 29 + .../generated/rpc/SessionFsExistsResult.java | 27 + .../generated/rpc/SessionFsMkdirParams.java | 33 + .../rpc/SessionFsReadFileParams.java | 29 + .../rpc/SessionFsReadFileResult.java | 27 + .../generated/rpc/SessionFsReaddirParams.java | 29 + .../generated/rpc/SessionFsReaddirResult.java | 28 + .../rpc/SessionFsReaddirWithTypesParams.java | 29 + .../rpc/SessionFsReaddirWithTypesResult.java | 58 + .../generated/rpc/SessionFsRenameParams.java | 31 + .../sdk/generated/rpc/SessionFsRmParams.java | 33 + .../rpc/SessionFsSetProviderParams.java | 51 + .../rpc/SessionFsSetProviderResult.java | 27 + .../generated/rpc/SessionFsStatParams.java | 29 + .../generated/rpc/SessionFsStatResult.java | 35 + .../rpc/SessionFsWriteFileParams.java | 33 + .../sdk/generated/rpc/SessionHistoryApi.java | 54 + .../rpc/SessionHistoryCompactParams.java | 27 + .../rpc/SessionHistoryCompactResult.java | 52 + .../rpc/SessionHistoryTruncateParams.java | 29 + .../rpc/SessionHistoryTruncateResult.java | 27 + .../sdk/generated/rpc/SessionLogParams.java | 57 + .../sdk/generated/rpc/SessionLogResult.java | 28 + .../sdk/generated/rpc/SessionMcpApi.java | 76 + .../rpc/SessionMcpDisableParams.java | 29 + .../rpc/SessionMcpDisableResult.java | 24 + .../generated/rpc/SessionMcpEnableParams.java | 29 + .../generated/rpc/SessionMcpEnableResult.java | 24 + .../generated/rpc/SessionMcpListParams.java | 27 + .../generated/rpc/SessionMcpListResult.java | 70 + .../generated/rpc/SessionMcpReloadParams.java | 27 + .../generated/rpc/SessionMcpReloadResult.java | 24 + .../sdk/generated/rpc/SessionModeApi.java | 50 + .../generated/rpc/SessionModeGetParams.java | 27 + .../generated/rpc/SessionModeGetResult.java | 49 + .../generated/rpc/SessionModeSetParams.java | 51 + .../generated/rpc/SessionModeSetResult.java | 49 + .../sdk/generated/rpc/SessionModelApi.java | 50 + .../rpc/SessionModelGetCurrentParams.java | 27 + .../rpc/SessionModelGetCurrentResult.java | 27 + .../rpc/SessionModelSwitchToParams.java | 78 + .../rpc/SessionModelSwitchToResult.java | 27 + .../generated/rpc/SessionPermissionsApi.java | 42 + ...sHandlePendingPermissionRequestParams.java | 30 + ...sHandlePendingPermissionRequestResult.java | 27 + .../sdk/generated/rpc/SessionPlanApi.java | 58 + .../rpc/SessionPlanDeleteParams.java | 27 + .../rpc/SessionPlanDeleteResult.java | 24 + .../generated/rpc/SessionPlanReadParams.java | 27 + .../generated/rpc/SessionPlanReadResult.java | 31 + .../rpc/SessionPlanUpdateParams.java | 29 + .../rpc/SessionPlanUpdateResult.java | 24 + .../sdk/generated/rpc/SessionPluginsApi.java | 40 + .../rpc/SessionPluginsListParams.java | 27 + .../rpc/SessionPluginsListResult.java | 42 + .../copilot/sdk/generated/rpc/SessionRpc.java | 104 ++ .../sdk/generated/rpc/SessionShellApi.java | 52 + .../generated/rpc/SessionShellExecParams.java | 33 + .../generated/rpc/SessionShellExecResult.java | 27 + .../generated/rpc/SessionShellKillParams.java | 53 + .../generated/rpc/SessionShellKillResult.java | 27 + .../sdk/generated/rpc/SessionSkillsApi.java | 76 + .../rpc/SessionSkillsDisableParams.java | 29 + .../rpc/SessionSkillsDisableResult.java | 24 + .../rpc/SessionSkillsEnableParams.java | 29 + .../rpc/SessionSkillsEnableResult.java | 24 + .../rpc/SessionSkillsListParams.java | 27 + .../rpc/SessionSkillsListResult.java | 46 + .../rpc/SessionSkillsReloadParams.java | 27 + .../rpc/SessionSkillsReloadResult.java | 24 + .../sdk/generated/rpc/SessionToolsApi.java | 42 + ...ssionToolsHandlePendingToolCallParams.java | 33 + ...ssionToolsHandlePendingToolCallResult.java | 27 + .../sdk/generated/rpc/SessionUiApi.java | 52 + .../rpc/SessionUiElicitationParams.java | 46 + .../rpc/SessionUiElicitationResult.java | 52 + ...ssionUiHandlePendingElicitationParams.java | 65 + ...ssionUiHandlePendingElicitationResult.java | 27 + .../sdk/generated/rpc/SessionUsageApi.java | 40 + .../rpc/SessionUsageGetMetricsParams.java | 27 + .../rpc/SessionUsageGetMetricsResult.java | 95 ++ .../generated/rpc/SessionWorkspaceApi.java | 60 + .../rpc/SessionWorkspaceCreateFileParams.java | 31 + .../rpc/SessionWorkspaceCreateFileResult.java | 24 + .../rpc/SessionWorkspaceListFilesParams.java | 27 + .../rpc/SessionWorkspaceListFilesResult.java | 28 + .../rpc/SessionWorkspaceReadFileParams.java | 29 + .../rpc/SessionWorkspaceReadFileResult.java | 27 + .../sdk/generated/rpc/SessionsForkParams.java | 29 + .../sdk/generated/rpc/SessionsForkResult.java | 27 + .../sdk/generated/rpc/ToolsListParams.java | 27 + .../sdk/generated/rpc/ToolsListResult.java | 45 + .../com/github/copilot/sdk/CopilotClient.java | 31 +- .../github/copilot/sdk/CopilotSession.java | 270 ++-- .../github/copilot/sdk/EventErrorHandler.java | 4 +- .../copilot/sdk/RpcHandlerDispatcher.java | 5 +- .../github/copilot/sdk/events/AbortEvent.java | 37 - .../sdk/events/AbstractSessionEvent.java | 179 --- .../sdk/events/AssistantIntentEvent.java | 37 - .../events/AssistantMessageDeltaEvent.java | 39 - .../sdk/events/AssistantMessageEvent.java | 95 -- .../events/AssistantReasoningDeltaEvent.java | 38 - .../sdk/events/AssistantReasoningEvent.java | 38 - .../events/AssistantStreamingDeltaEvent.java | 37 - .../sdk/events/AssistantTurnEndEvent.java | 37 - .../sdk/events/AssistantTurnStartEvent.java | 38 - .../sdk/events/AssistantUsageEvent.java | 78 - .../sdk/events/CapabilitiesChangedEvent.java | 44 - .../sdk/events/CommandCompletedEvent.java | 37 - .../sdk/events/CommandExecuteEvent.java | 43 - .../sdk/events/CommandQueuedEvent.java | 38 - .../sdk/events/ElicitationRequestedEvent.java | 54 - .../events/ExitPlanModeCompletedEvent.java | 37 - .../events/ExitPlanModeRequestedEvent.java | 39 - .../events/ExternalToolCompletedEvent.java | 40 - .../events/ExternalToolRequestedEvent.java | 43 - .../copilot/sdk/events/HookEndEvent.java | 43 - .../copilot/sdk/events/HookStartEvent.java | 38 - .../events/PendingMessagesModifiedEvent.java | 37 - .../sdk/events/PermissionCompletedEvent.java | 45 - .../sdk/events/PermissionRequestedEvent.java | 44 - .../SessionCompactionCompleteEvent.java | 54 - .../events/SessionCompactionStartEvent.java | 37 - .../events/SessionContextChangedEvent.java | 37 - .../copilot/sdk/events/SessionErrorEvent.java | 39 - .../sdk/events/SessionEventParser.java | 144 -- .../sdk/events/SessionHandoffEvent.java | 47 - .../copilot/sdk/events/SessionIdleEvent.java | 37 - .../copilot/sdk/events/SessionInfoEvent.java | 37 - .../sdk/events/SessionModeChangedEvent.java | 38 - .../sdk/events/SessionModelChangeEvent.java | 38 - .../sdk/events/SessionPlanChangedEvent.java | 37 - .../sdk/events/SessionResumeEvent.java | 40 - .../sdk/events/SessionShutdownEvent.java | 71 - .../events/SessionSnapshotRewindEvent.java | 40 - .../copilot/sdk/events/SessionStartEvent.java | 41 - .../sdk/events/SessionTaskCompleteEvent.java | 37 - .../sdk/events/SessionTruncationEvent.java | 44 - .../sdk/events/SessionUsageInfoEvent.java | 39 - .../SessionWorkspaceFileChangedEvent.java | 38 - .../copilot/sdk/events/SkillInvokedEvent.java | 46 - .../sdk/events/SubagentCompletedEvent.java | 38 - .../sdk/events/SubagentDeselectedEvent.java | 37 - .../sdk/events/SubagentFailedEvent.java | 38 - .../sdk/events/SubagentSelectedEvent.java | 44 - .../sdk/events/SubagentStartedEvent.java | 39 - .../sdk/events/SystemMessageEvent.java | 40 - .../sdk/events/SystemNotificationEvent.java | 37 - .../events/ToolExecutionCompleteEvent.java | 60 - .../ToolExecutionPartialResultEvent.java | 38 - .../events/ToolExecutionProgressEvent.java | 42 - .../sdk/events/ToolExecutionStartEvent.java | 40 - .../sdk/events/ToolUserRequestedEvent.java | 38 - .../sdk/events/UnknownSessionEvent.java | 74 - .../copilot/sdk/events/UserMessageEvent.java | 62 - .../copilot/sdk/events/package-info.java | 91 -- .../copilot/sdk/json/ResumeSessionConfig.java | 8 +- .../copilot/sdk/json/SessionConfig.java | 8 +- .../com/github/copilot/sdk/package-info.java | 4 +- src/site/markdown/advanced.md | 4 +- src/site/markdown/cookbook/error-handling.md | 8 +- .../markdown/cookbook/managing-local-files.md | 8 +- .../markdown/cookbook/multiple-sessions.md | 2 +- .../markdown/cookbook/persisting-sessions.md | 6 +- .../markdown/cookbook/pr-visualization.md | 4 +- src/site/markdown/documentation.md | 6 +- src/site/markdown/getting-started.md | 12 +- src/site/markdown/index.md | 8 +- .../copilot/sdk/ClosedSessionGuardTest.java | 2 +- .../github/copilot/sdk/CompactionTest.java | 12 +- .../github/copilot/sdk/ConfigCloneTest.java | 6 +- .../github/copilot/sdk/CopilotClientTest.java | 77 +- .../copilot/sdk/CopilotSessionTest.java | 51 +- .../github/copilot/sdk/ErrorHandlingTest.java | 10 +- .../copilot/sdk/ExecutorWiringTest.java | 2 +- .../copilot/sdk/ForwardCompatibilityTest.java | 57 +- .../github/copilot/sdk/McpAndAgentsTest.java | 2 +- .../github/copilot/sdk/MetadataApiTest.java | 76 +- .../github/copilot/sdk/PermissionsTest.java | 4 +- .../github/copilot/sdk/RpcWrappersTest.java | 471 ++++++ ...a => SessionEventDeserializationTest.java} | 338 +++-- .../copilot/sdk/SessionEventHandlingTest.java | 27 +- .../copilot/sdk/SessionEventsE2ETest.java | 41 +- .../com/github/copilot/sdk/SkillsTest.java | 2 +- .../copilot/sdk/StreamingFidelityTest.java | 14 +- .../java/com/github/copilot/sdk/TestUtil.java | 101 ++ .../copilot/sdk/TimeoutEdgeCaseTest.java | 2 +- .../com/github/copilot/sdk/ToolsTest.java | 2 +- .../copilot/sdk/ZeroTimeoutContractTest.java | 2 +- 329 files changed, 13313 insertions(+), 3485 deletions(-) create mode 100644 .github/workflows/codegen-check.yml create mode 100644 .github/workflows/update-copilot-dependency.yml create mode 100644 scripts/codegen/.gitignore create mode 100644 scripts/codegen/java.ts create mode 100644 scripts/codegen/package-lock.json create mode 100644 scripts/codegen/package.json create mode 100644 src/generated/java/com/github/copilot/sdk/generated/AbortEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/AssistantIntentEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/AssistantMessageDeltaEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/AssistantMessageEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/AssistantReasoningDeltaEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/AssistantReasoningEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/AssistantStreamingDeltaEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/AssistantTurnEndEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/AssistantTurnStartEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/AssistantUsageEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/CapabilitiesChangedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/CommandCompletedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/CommandExecuteEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/CommandQueuedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/CommandsChangedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/ElicitationCompletedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/ElicitationRequestedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/ExitPlanModeCompletedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/ExitPlanModeRequestedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/ExternalToolCompletedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/ExternalToolRequestedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/HookEndEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/HookStartEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/McpOauthCompletedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/McpOauthRequiredEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/PendingMessagesModifiedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/PermissionCompletedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/PermissionRequestedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SamplingCompletedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SamplingRequestedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionBackgroundTasksChangedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionCompactionCompleteEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionCompactionStartEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionContextChangedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionCustomAgentsUpdatedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionErrorEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionExtensionsLoadedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionHandoffEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionIdleEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionInfoEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionMcpServerStatusChangedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionMcpServersLoadedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionModeChangedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionModelChangeEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionPlanChangedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionRemoteSteerableChangedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionResumeEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionShutdownEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionSkillsLoadedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionSnapshotRewindEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionStartEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionTaskCompleteEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionTitleChangedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionToolsUpdatedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionTruncationEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionUsageInfoEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionWarningEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SessionWorkspaceFileChangedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SkillInvokedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SubagentCompletedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SubagentDeselectedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SubagentFailedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SubagentSelectedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SubagentStartedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SystemMessageEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/SystemNotificationEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/ToolExecutionCompleteEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/ToolExecutionPartialResultEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/ToolExecutionProgressEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/ToolExecutionStartEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/ToolUserRequestedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/UnknownSessionEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/UserInputCompletedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/UserInputRequestedEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/UserMessageEvent.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/AccountGetQuotaResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/McpConfigAddParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/McpConfigListResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/McpConfigRemoveParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/McpConfigUpdateParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/McpDiscoverParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/McpDiscoverResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/ModelsListResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/PingParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/PingResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/RpcCaller.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/RpcMapper.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/ServerAccountApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/ServerMcpApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/ServerMcpConfigApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/ServerModelsApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/ServerRpc.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/ServerSessionFsApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/ServerSessionsApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/ServerToolsApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentDeselectParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentDeselectResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentGetCurrentParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentGetCurrentResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentListParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentListResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentReloadParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentReloadResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentSelectParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentSelectResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsHandlePendingCommandParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsHandlePendingCommandResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsDisableParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsDisableResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsEnableParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsEnableResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsListParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsListResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsReloadParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsReloadResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFleetApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFleetStartParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFleetStartResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsAppendFileParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsExistsParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsExistsResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsMkdirParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReadFileParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReadFileResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReaddirParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReaddirResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReaddirWithTypesParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReaddirWithTypesResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsRenameParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsRmParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsSetProviderParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsSetProviderResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsStatParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsStatResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsWriteFileParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryCompactParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryCompactResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryTruncateParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryTruncateResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionLogParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionLogResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpDisableParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpDisableResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpEnableParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpEnableResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpListParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpListResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpReloadParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpReloadResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeGetParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeGetResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeSetParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeSetResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelGetCurrentParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelGetCurrentResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelSwitchToParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelSwitchToResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsHandlePendingPermissionRequestParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsHandlePendingPermissionRequestResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanDeleteParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanDeleteResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanReadParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanReadResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanUpdateParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanUpdateResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPluginsApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPluginsListParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPluginsListResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionRpc.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellExecParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellExecResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellKillParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellKillResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsDisableParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsDisableResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsEnableParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsEnableResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsListParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsListResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsReloadParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsReloadResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsHandlePendingToolCallParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsHandlePendingToolCallResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiElicitationParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiElicitationResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiHandlePendingElicitationParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiHandlePendingElicitationResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUsageApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUsageGetMetricsParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUsageGetMetricsResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceApi.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceCreateFileParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceCreateFileResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceListFilesParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceListFilesResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceReadFileParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceReadFileResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionsForkParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/SessionsForkResult.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/ToolsListParams.java create mode 100644 src/generated/java/com/github/copilot/sdk/generated/rpc/ToolsListResult.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/AbortEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/AbstractSessionEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/AssistantIntentEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/AssistantMessageDeltaEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/AssistantMessageEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/AssistantReasoningDeltaEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/AssistantReasoningEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/AssistantStreamingDeltaEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/AssistantTurnEndEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/AssistantTurnStartEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/AssistantUsageEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/CapabilitiesChangedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/CommandCompletedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/CommandExecuteEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/CommandQueuedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/ElicitationRequestedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/ExitPlanModeCompletedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/ExitPlanModeRequestedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/ExternalToolCompletedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/ExternalToolRequestedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/HookEndEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/HookStartEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/PendingMessagesModifiedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/PermissionCompletedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/PermissionRequestedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SessionCompactionCompleteEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SessionCompactionStartEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SessionContextChangedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SessionErrorEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SessionEventParser.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SessionHandoffEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SessionIdleEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SessionInfoEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SessionModeChangedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SessionModelChangeEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SessionPlanChangedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SessionResumeEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SessionShutdownEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SessionSnapshotRewindEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SessionStartEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SessionTaskCompleteEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SessionTruncationEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SessionUsageInfoEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SessionWorkspaceFileChangedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SkillInvokedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SubagentCompletedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SubagentDeselectedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SubagentFailedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SubagentSelectedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SubagentStartedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SystemMessageEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/SystemNotificationEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/ToolExecutionCompleteEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/ToolExecutionPartialResultEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/ToolExecutionProgressEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/ToolExecutionStartEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/ToolUserRequestedEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/UnknownSessionEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/UserMessageEvent.java delete mode 100644 src/main/java/com/github/copilot/sdk/events/package-info.java create mode 100644 src/test/java/com/github/copilot/sdk/RpcWrappersTest.java rename src/test/java/com/github/copilot/sdk/{SessionEventParserTest.java => SessionEventDeserializationTest.java} (90%) create mode 100644 src/test/java/com/github/copilot/sdk/TestUtil.java diff --git a/.gitattributes b/.gitattributes index c1965c216..adb3de78e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ -.github/workflows/*.lock.yml linguist-generated=true merge=ours \ No newline at end of file +.github/workflows/*.lock.yml linguist-generated=true merge=ours +src/generated/java/** eol=lf linguist-generated=true diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index c1a2d8dec..08f0a5758 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -77,7 +77,7 @@ mvn test -Dtest=CopilotClientTest - `com.github.copilot.sdk` - Core classes (CopilotClient, CopilotSession, JsonRpcClient) - `com.github.copilot.sdk.json` - DTOs, request/response types, handler interfaces (SessionConfig, MessageOptions, ToolDefinition, etc.) -- `com.github.copilot.sdk.events` - Event types for session streaming (AssistantMessageEvent, SessionIdleEvent, ToolExecutionStartEvent, etc.) +- `com.github.copilot.sdk.generated` - Generated event types for session streaming (SessionEvent, AssistantMessageEvent, SessionIdleEvent, ToolExecutionStartEvent, etc.) ### Test Infrastructure diff --git a/.github/prompts/agentic-merge-reference-impl.prompt.md b/.github/prompts/agentic-merge-reference-impl.prompt.md index 1c19b6f1c..88cc2bdfe 100644 --- a/.github/prompts/agentic-merge-reference-impl.prompt.md +++ b/.github/prompts/agentic-merge-reference-impl.prompt.md @@ -2,6 +2,43 @@ You are an expert Java developer tasked with porting changes from the reference implementation of the Copilot SDK (primarily the .NET implementation) to this Java SDK. +## ❌❌❌ ABSOLUTE PROHIBITION: DO NOT TOUCH GENERATED CODE ❌❌❌ + +> ### 🚫 THE FILES UNDER `src/generated/java/` ARE FORBIDDEN 🚫 +> +> **NEVER, UNDER ANY CIRCUMSTANCES, MODIFY ANY FILE IN `src/generated/java/`.** +> +> These files are AUTO-GENERATED by `scripts/codegen/java.ts` and MUST NOT be hand-edited. +> They are regenerated automatically when the `@github/copilot` npm package version is updated. +> +> ❌ DO NOT edit `src/generated/java/**/*.java` +> ❌ DO NOT create new files in `src/generated/java/` +> ❌ DO NOT delete files from `src/generated/java/` +> ❌ DO NOT "fix" or "improve" generated code — it will be overwritten +> +> **IF ANY CHANGE YOU NEED TO MAKE REQUIRES TOUCHING `src/generated/java/`:** +> +> 1. **STOP IMMEDIATELY** — do not make the change +> 2. **FAIL the agentic sync** — do not attempt to work around this restriction +> 3. **Push an explanatory commit** with a message such as: +> ``` +> SYNC BLOCKED: Required change needs generated code update +> +> The reference implementation change '' requires updates +> to the generated RPC/event types in src/generated/java/. These files +> cannot be hand-edited — they must be regenerated. +> +> ACTION REQUIRED: Re-run the update-copilot-dependency.yml workflow +> to update the @github/copilot npm package and regenerate the Java +> source files before this sync can be completed. +> ``` +> 4. **Document in the PR body** which reference implementation changes were blocked and why +> 5. **Do NOT attempt to work around this restriction** by making equivalent changes elsewhere +> +> The correct way to update generated code is: +> - Trigger the `update-copilot-dependency.yml` workflow with the new `@github/copilot` version +> - That workflow updates `package.json`, regenerates all files in `src/generated/java/`, and opens a PR + ## ⚠️ IMPORTANT: Java SDK Design Takes Priority **The current design and architecture of the Java SDK is the priority.** When porting changes from the reference implementation: @@ -101,7 +138,7 @@ For each change in the reference implementation diff, determine: | `dotnet/src/Client.cs` | `src/main/java/com/github/copilot/sdk/CopilotClient.java` | | `dotnet/src/Session.cs` | `src/main/java/com/github/copilot/sdk/CopilotSession.java` | | `dotnet/src/Types.cs` | `src/main/java/com/github/copilot/sdk/types/*.java` | -| `dotnet/src/Generated/*.cs` | `src/main/java/com/github/copilot/sdk/types/*.java` | +| `dotnet/src/Generated/*.cs` | ❌ **DO NOT TOUCH** `src/generated/java/**` — see top of this file | | `dotnet/test/*.cs` | `src/test/java/com/github/copilot/sdk/*Test.java` | | `docs/getting-started.md` | `README.md` and `src/site/markdown/*.md` | | `docs/*.md` (new files) | `src/site/markdown/*.md` + update `src/site/site.xml` | @@ -111,6 +148,10 @@ For each change in the reference implementation diff, determine: ## Step 5: Apply Changes to Java SDK +> ### ❌❌❌ REMINDER: `src/generated/java/` IS FORBIDDEN ❌❌❌ +> Any change that requires modifying `src/generated/java/` MUST stop the sync. +> See the **ABSOLUTE PROHIBITION** section at the top of this file for required actions. + When porting changes: ### ⚠️ Priority: Preserve Java SDK Design @@ -400,6 +441,7 @@ Before finishing: ## Checklist +- [ ] ❌ **VERIFIED: No files in `src/generated/java/` were modified** (if any were needed, sync was stopped per ABSOLUTE PROHIBITION above) - [ ] New branch created from `main` - [ ] Copilot CLI updated to latest version - [ ] README.md updated with minimum CLI version requirement @@ -430,6 +472,7 @@ Before finishing: ## Notes +- ❌❌❌ **`src/generated/java/` IS FORBIDDEN** — NEVER modify generated files; re-run `update-copilot-dependency.yml` instead ❌❌❌ - The reference implementation SDK is at: `https://github.com/github/copilot-sdk.git` - Primary reference implementation is in `dotnet/` folder - This Java SDK targets Java 17+ diff --git a/.github/prompts/coding-agent-merge-reference-impl-instructions.md b/.github/prompts/coding-agent-merge-reference-impl-instructions.md index cee6ef8a7..c93af9a1a 100644 --- a/.github/prompts/coding-agent-merge-reference-impl-instructions.md +++ b/.github/prompts/coding-agent-merge-reference-impl-instructions.md @@ -17,3 +17,17 @@ Add the 'reference-impl-sync' label to the existing PR by running this command i If after analyzing the reference implementation diff there are no relevant changes to port to the Java SDK, push an empty commit with a message explaining why no changes were needed, so the PR reflects the analysis outcome. The repository maintainer will close the PR and issue manually. + +❌❌❌ ABSOLUTE PROHIBITION ❌❌❌ + +NEVER MODIFY ANY FILE UNDER src/generated/java/ — THESE FILES ARE AUTO-GENERATED AND FORBIDDEN. + +If any change requires modifying src/generated/java/: +1. STOP IMMEDIATELY — do not make the change +2. FAIL the sync with an explanatory commit message +3. Instruct the maintainer to re-run update-copilot-dependency.yml to regenerate these files + +See the ABSOLUTE PROHIBITION section in .github/prompts/agentic-merge-reference-impl.prompt.md +for the full required procedure and commit message template. + +❌❌❌ END ABSOLUTE PROHIBITION ❌❌❌ diff --git a/.github/workflows/codegen-check.yml b/.github/workflows/codegen-check.yml new file mode 100644 index 000000000..675629c1e --- /dev/null +++ b/.github/workflows/codegen-check.yml @@ -0,0 +1,44 @@ +name: "Codegen Check" + +on: + push: + branches: + - main + pull_request: + paths: + - 'scripts/codegen/**' + - 'src/generated/java/**' + - '.github/workflows/codegen-check.yml' + workflow_dispatch: + +permissions: + contents: read + +jobs: + check: + name: "Verify generated files are up-to-date" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6 + with: + node-version: 22 + + - name: Install codegen dependencies + working-directory: ./scripts/codegen + run: npm ci + + - name: Run codegen + working-directory: ./scripts/codegen + run: npm run generate + + - name: Check for uncommitted changes + run: | + if [ -n "$(git status --porcelain)" ]; then + echo "::error::Generated files are out of date. Run 'cd scripts/codegen && npm run generate' and commit the changes." + git diff --stat + git diff + exit 1 + fi + echo "✅ Generated files are up-to-date" diff --git a/.github/workflows/update-copilot-dependency.yml b/.github/workflows/update-copilot-dependency.yml new file mode 100644 index 000000000..bb86bfd83 --- /dev/null +++ b/.github/workflows/update-copilot-dependency.yml @@ -0,0 +1,144 @@ +name: "Update @github/copilot Dependency" + +on: + workflow_dispatch: + inputs: + version: + description: 'Target version of @github/copilot (e.g. 1.0.24)' + required: true + type: string + +permissions: + contents: write + pull-requests: write + +jobs: + update: + name: "Update @github/copilot to ${{ inputs.version }}" + runs-on: ubuntu-latest + steps: + - name: Validate version input + env: + VERSION: ${{ inputs.version }} + run: | + if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9._-]+)?$ ]]; then + echo "::error::Invalid version format '$VERSION'. Expected semver (e.g. 1.0.24)." + exit 1 + fi + + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6 + with: + node-version: 22 + + - name: Update @github/copilot in scripts/codegen + env: + VERSION: ${{ inputs.version }} + working-directory: ./scripts/codegen + # npm install updates package.json and package-lock.json to the new + # version; npm ci (below) then does a clean, reproducible install from + # the updated lock file. Both steps are required: npm install alone + # leaves leftover packages, while npm ci alone cannot change the pinned + # version in the lock file. + run: npm install "@github/copilot@$VERSION" + + - name: Install codegen dependencies + working-directory: ./scripts/codegen + run: npm ci + + - name: Run codegen + working-directory: ./scripts/codegen + run: npm run generate + + - uses: ./.github/actions/setup-copilot + + - name: Verify generated code against schema + env: + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + run: | + cat > /tmp/verify-codegen-prompt.txt << 'PROMPT_EOF' + You are running inside the copilot-sdk-java repository. + The code generator has just run and produced Java source files under + src/generated/java/com/github/copilot/sdk/generated/rpc/. + + Your task is to spot-check the generated API classes against the source + JSON schema to verify the generator produced correct output. + + **Critical constraint: Do NOT modify any files. This is a read-only + verification. Use only read/inspect operations.** + + **Steps:** + 1. Read the API schema at: + scripts/codegen/node_modules/@github/copilot/schemas/api.schema.json + + 2. Pick these 3 generated API classes to verify: + - src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsApi.java + - src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiApi.java + - src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsApi.java + + 3. For each class, verify: + - Every RPC method in the schema's corresponding namespace has a + matching Java method in the generated class + - Parameter record fields match the JSON schema property names + - Java types are consistent with JSON schema types (String for + "string", Integer/int for "integer", Boolean/boolean for + "boolean", List for "array", Map or a generated class for + "object", etc.) + - No extra methods exist in the Java class that are not in the + schema + + 4. Print a summary table of what was checked and the result for each + method. + + 5. If ANY mismatch is found, print the details and exit with a + non-zero code. + If all checks pass, print "Schema verification passed" and exit 0. + PROMPT_EOF + + copilot --yolo --prompt "$(cat /tmp/verify-codegen-prompt.txt)" + + - name: Create pull request + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ inputs.version }} + run: | + BRANCH="update-copilot-$VERSION" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + if git rev-parse --verify "origin/$BRANCH" >/dev/null 2>&1; then + git checkout "$BRANCH" + git reset --hard HEAD + else + git checkout -b "$BRANCH" + fi + + git add -A + + if git diff --cached --quiet; then + echo "No changes detected; skipping commit and PR creation." + exit 0 + fi + + git commit -m "Update @github/copilot to $VERSION + + - Updated @github/copilot in scripts/codegen + - Re-ran Java code generator" + git push origin "$BRANCH" --force-with-lease + + if gh pr view "$BRANCH" >/dev/null 2>&1; then + echo "Pull request for branch '$BRANCH' already exists; updated branch only." + else + gh pr create \ + --title "Update @github/copilot to $VERSION" \ + --body "Automated update of \`@github/copilot\` to version \`$VERSION\`. + + ### Changes + - Updated \`@github/copilot\` in \`scripts/codegen/package.json\` + - Re-ran Java code generator (\`scripts/codegen\`) + + > Created by the **Update @github/copilot Dependency** workflow." \ + --base main \ + --head "$BRANCH" + fi diff --git a/.gitignore b/.gitignore index f079a3d20..35ea546f0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,10 +5,11 @@ examples-test/ blog-copilotsdk/ .claude/worktrees smoke-test -*job-logs.txt +*job-logs.txt* temporary-prompts/ changebundle.txt* .classpath .project .settings +scripts/codegen/node_modules/ *~ diff --git a/README.md b/README.md index d425fa4eb..95372e91f 100644 --- a/README.md +++ b/README.md @@ -67,8 +67,8 @@ implementation 'com.github:copilot-sdk-java:0.2.2-java.1' ```java import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.events.AssistantMessageEvent; -import com.github.copilot.sdk.events.SessionUsageInfoEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; +import com.github.copilot.sdk.generated.SessionUsageInfoEvent; import com.github.copilot.sdk.json.CopilotClientOptions; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 33c9ac5f2..9a6f3761b 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -11,9 +11,9 @@ - + - + diff --git a/config/spotbugs/spotbugs-exclude.xml b/config/spotbugs/spotbugs-exclude.xml index 7f3b068cb..1c7d415f6 100644 --- a/config/spotbugs/spotbugs-exclude.xml +++ b/config/spotbugs/spotbugs-exclude.xml @@ -2,7 +2,7 @@ - + diff --git a/docs/WORKFLOWS.md b/docs/WORKFLOWS.md index 1cbb22b36..3df254890 100644 --- a/docs/WORKFLOWS.md +++ b/docs/WORKFLOWS.md @@ -5,6 +5,8 @@ | Workflow | Description | Triggers | Schedule | |----------|-------------|----------|----------| | [Build & Test](workflows/build-test.yml) | Builds, lints, and tests the Java SDK | `push` (main), `pull_request`, `merge_group`, `workflow_dispatch` | Sundays at 00:00 UTC | +| [Codegen Check](workflows/codegen-check.yml) | Verifies that generated Java files are up-to-date with the JSON schemas | `push` (main), `pull_request`, `workflow_dispatch` | — | +| [Update @github/copilot Dependency](workflows/update-copilot-dependency.yml) | Updates the `@github/copilot` npm package, re-runs code generation, and opens a PR | `workflow_dispatch` | — | | [Deploy Documentation](workflows/deploy-site.yml) | Generates and deploys versioned docs to GitHub Pages | `workflow_run` (after Build & Test), `release`, `workflow_dispatch` | — | | [Publish to Maven Central](workflows/publish-maven.yml) | Releases the SDK to Maven Central and creates a GitHub Release | `workflow_dispatch` | — | | [Weekly Reference Implementation Sync](workflows/weekly-reference-impl-sync.yml) | Checks for new reference implementation commits and creates an issue for Copilot to merge | `workflow_dispatch` | Mondays at 10:00 UTC | @@ -87,6 +89,42 @@ Auto-generated compiled workflow produced by `gh aw compile` from the correspond --- +## Codegen Check + +**File:** [`codegen-check.yml`](workflows/codegen-check.yml) + +Verifies that the generated Java source files in `src/generated/java/` are up-to-date with the JSON schemas distributed in the `@github/copilot` npm package. + +Steps: +1. Installs the codegen dependencies from `scripts/codegen/` +2. Runs the Java code generator (`npm run generate`) +3. Fails with a diff if any generated file differs from what is committed + +Run this locally with: +```bash +cd scripts/codegen && npm ci && npm run generate +``` + +If changes appear, commit the updated generated files. + +--- + +## Update @github/copilot Dependency + +**File:** [`update-copilot-dependency.yml`](workflows/update-copilot-dependency.yml) + +Manual workflow triggered when a new version of the `@github/copilot` npm package is published. Accepts a `version` input (e.g. `1.0.25`). + +Steps: +1. Updates `@github/copilot` in `scripts/codegen/package.json` +2. Re-runs the Java code generator +3. Commits the updated `package.json`, `package-lock.json`, and all regenerated Java files +4. Opens (or updates) a pull request for review + +The resulting PR will be automatically validated by the **Codegen Check** workflow. + +--- + ## Copilot Setup Steps **File:** [`copilot-setup-steps.yml`](workflows/copilot-setup-steps.yml) diff --git a/jbang-example.java b/jbang-example.java index dd1f80762..dd3f1de78 100644 --- a/jbang-example.java +++ b/jbang-example.java @@ -1,8 +1,8 @@ ! //DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.events.AssistantMessageEvent; -import com.github.copilot.sdk.events.SessionUsageInfoEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; +import com.github.copilot.sdk.generated.SessionUsageInfoEvent; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.SessionConfig; diff --git a/pom.xml b/pom.xml index b61c36166..562b77ed5 100644 --- a/pom.xml +++ b/pom.xml @@ -255,12 +255,35 @@ + + + org.codehaus.mojo + build-helper-maven-plugin + 3.6.1 + + + add-generated-source + generate-sources + + add-source + + + + ${project.basedir}/src/generated/java + + + + + com.diffplug.spotless spotless-maven-plugin 2.44.5 + + src/generated/java/**/*.java + 4.33 @@ -627,5 +650,103 @@ + + + update-schemas-from-npm-artifact + + + + org.codehaus.mojo + exec-maven-plugin + 3.6.2 + + + update-copilot-schema-version + generate-sources + + exec + + + npm + ${project.basedir}/scripts/codegen + + install + @github/copilot@${copilot.schema.version} + + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.5.0 + + + require-schema-version + validate + + enforce + + + + + copilot.schema.version + You must specify -Dcopilot.schema.version=VERSION (e.g. 1.0.25) + + + + + + + + + + + + codegen + + + + org.codehaus.mojo + exec-maven-plugin + 3.6.2 + + + codegen-npm-install + generate-sources + + exec + + + npm + ${project.basedir}/scripts/codegen + + ci + + + + + codegen-generate + generate-sources + + exec + + + npm + ${project.basedir}/scripts/codegen + + run + generate + + + + + + + + diff --git a/scripts/codegen/.gitignore b/scripts/codegen/.gitignore new file mode 100644 index 000000000..c2658d7d1 --- /dev/null +++ b/scripts/codegen/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/scripts/codegen/java.ts b/scripts/codegen/java.ts new file mode 100644 index 000000000..84b9e8bf1 --- /dev/null +++ b/scripts/codegen/java.ts @@ -0,0 +1,1322 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +/** + * Java code generator for session-events and RPC types. + * Generates Java source files under src/generated/java/ from JSON Schema files. + */ + +import fs from "fs/promises"; +import path from "path"; +import { fileURLToPath } from "url"; +import type { JSONSchema7 } from "json-schema"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +/** Root of the copilot-sdk-java repo */ +const REPO_ROOT = path.resolve(__dirname, "../.."); + +/** Event types to exclude from generation (internal/legacy types) */ +const EXCLUDED_EVENT_TYPES = new Set(["session.import_legacy"]); + +const AUTO_GENERATED_HEADER = `// AUTO-GENERATED FILE - DO NOT EDIT`; +const GENERATED_FROM_SESSION_EVENTS = `// Generated from: session-events.schema.json`; +const GENERATED_FROM_API = `// Generated from: api.schema.json`; +const GENERATED_ANNOTATION = `@javax.annotation.processing.Generated("copilot-sdk-codegen")`; +const COPYRIGHT = `/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n *--------------------------------------------------------------------------------------------*/`; + +// ── Naming utilities ───────────────────────────────────────────────────────── + +function toPascalCase(name: string): string { + return name.split(/[-_.]/).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(""); +} + +function toJavaClassName(typeName: string): string { + return typeName.split(/[._]/).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(""); +} + +function toCamelCase(name: string): string { + const pascal = toPascalCase(name); + return pascal.charAt(0).toLowerCase() + pascal.slice(1); +} + +function toEnumConstant(value: string): string { + return value.toUpperCase().replace(/[-. ]/g, "_"); +} + +// ── Schema path resolution ─────────────────────────────────────────────────── + +async function getSessionEventsSchemaPath(): Promise { + const candidates = [ + path.join(REPO_ROOT, "scripts/codegen/node_modules/@github/copilot/schemas/session-events.schema.json"), + path.join(REPO_ROOT, "nodejs/node_modules/@github/copilot/schemas/session-events.schema.json"), + ]; + for (const p of candidates) { + try { + await fs.access(p); + return p; + } catch { + // try next + } + } + throw new Error("session-events.schema.json not found. Run 'npm ci' in scripts/codegen first."); +} + +async function getApiSchemaPath(): Promise { + const candidates = [ + path.join(REPO_ROOT, "scripts/codegen/node_modules/@github/copilot/schemas/api.schema.json"), + path.join(REPO_ROOT, "nodejs/node_modules/@github/copilot/schemas/api.schema.json"), + ]; + for (const p of candidates) { + try { + await fs.access(p); + return p; + } catch { + // try next + } + } + throw new Error("api.schema.json not found. Run 'npm ci' in scripts/codegen first."); +} + +// ── File writing ───────────────────────────────────────────────────────────── + +async function writeGeneratedFile(relativePath: string, content: string): Promise { + const fullPath = path.join(REPO_ROOT, relativePath); + await fs.mkdir(path.dirname(fullPath), { recursive: true }); + await fs.writeFile(fullPath, content, "utf-8"); + console.log(` ✓ ${relativePath}`); + return fullPath; +} + +// ── Java type mapping ───────────────────────────────────────────────────────── + +interface JavaTypeResult { + javaType: string; + imports: Set; +} + +function schemaTypeToJava( + schema: JSONSchema7, + required: boolean, + context: string, + propName: string, + nestedTypes: Map +): JavaTypeResult { + const imports = new Set(); + + if (schema.anyOf) { + const hasNull = schema.anyOf.some((s) => typeof s === "object" && (s as JSONSchema7).type === "null"); + const nonNull = schema.anyOf.filter((s) => typeof s === "object" && (s as JSONSchema7).type !== "null"); + if (nonNull.length === 1) { + const result = schemaTypeToJava(nonNull[0] as JSONSchema7, required && !hasNull, context, propName, nestedTypes); + return result; + } + // Multi-branch anyOf: fall through to Object, matching the C# generator's + // behavior. Java has no union types, so Object is the correct erasure for + // anyOf[string, object] and similar multi-variant schemas. + console.warn(`[codegen] ${context}.${propName}: anyOf with ${nonNull.length} non-null branches — falling back to Object`); + return { javaType: "Object", imports }; + } + + if (schema.type === "string") { + if (schema.format === "uuid") { + imports.add("java.util.UUID"); + return { javaType: "UUID", imports }; + } + if (schema.format === "date-time") { + imports.add("java.time.OffsetDateTime"); + return { javaType: "OffsetDateTime", imports }; + } + if (schema.enum && Array.isArray(schema.enum)) { + const enumName = `${context}${toPascalCase(propName)}`; + nestedTypes.set(enumName, { + kind: "enum", + name: enumName, + values: schema.enum as string[], + description: schema.description, + }); + return { javaType: enumName, imports }; + } + return { javaType: "String", imports }; + } + + if (Array.isArray(schema.type)) { + const nonNullTypes = schema.type.filter((t) => t !== "null"); + if (nonNullTypes.length === 1) { + const baseSchema = { ...schema, type: nonNullTypes[0] }; + return schemaTypeToJava(baseSchema as JSONSchema7, required, context, propName, nestedTypes); + } + } + + if (schema.type === "integer") { + // JSON Schema "integer" maps to Long (boxed — always used for records). + // Use primitive long for required fields in mutable-bean contexts if needed. + return { javaType: required ? "long" : "Long", imports }; + } + + if (schema.type === "number") { + return { javaType: required ? "double" : "Double", imports }; + } + + if (schema.type === "boolean") { + return { javaType: required ? "boolean" : "Boolean", imports }; + } + + if (schema.type === "array") { + const items = schema.items as JSONSchema7 | undefined; + if (items) { + const itemResult = schemaTypeToJava(items, true, context, propName + "Item", nestedTypes); + imports.add("java.util.List"); + for (const imp of itemResult.imports) imports.add(imp); + return { javaType: `List<${itemResult.javaType}>`, imports }; + } + imports.add("java.util.List"); + console.warn(`[codegen] ${context}.${propName}: array without typed items — falling back to List`); + return { javaType: "List", imports }; + } + + if (schema.type === "object") { + if (schema.properties && Object.keys(schema.properties).length > 0) { + const nestedName = `${context}${toPascalCase(propName)}`; + if (!nestedTypes.has(nestedName)) { + nestedTypes.set(nestedName, { + kind: "class", + name: nestedName, + schema, + description: schema.description, + }); + } + return { javaType: nestedName, imports }; + } + if (schema.additionalProperties) { + const valueSchema = typeof schema.additionalProperties === "object" + ? schema.additionalProperties as JSONSchema7 + : { type: "object" } as JSONSchema7; + const valueResult = schemaTypeToJava(valueSchema, true, context, propName + "Value", nestedTypes); + imports.add("java.util.Map"); + for (const imp of valueResult.imports) imports.add(imp); + return { javaType: `Map`, imports }; + } + imports.add("java.util.Map"); + console.warn(`[codegen] ${context}.${propName}: object without typed properties or additionalProperties — falling back to Map`); + return { javaType: "Map", imports }; + } + + if (schema.$ref) { + const refName = schema.$ref.split("/").pop()!; + return { javaType: refName, imports }; + } + + console.warn(`[codegen] ${context}.${propName}: unrecognized schema (type=${JSON.stringify(schema.type)}) — falling back to Object`); + return { javaType: "Object", imports }; +} + +// ── Class definitions ───────────────────────────────────────────────────────── + +interface JavaClassDef { + kind: "class" | "enum"; + name: string; + description?: string; + schema?: JSONSchema7; + values?: string[]; // for enum +} + +// ── Session Events codegen ──────────────────────────────────────────────────── + +interface EventVariant { + typeName: string; + className: string; + dataSchema: JSONSchema7 | null; + description?: string; +} + +function extractEventVariants(schema: JSONSchema7): EventVariant[] { + const sessionEvent = (schema.definitions as Record)?.SessionEvent; + if (!sessionEvent?.anyOf) throw new Error("Schema must have SessionEvent definition with anyOf"); + + return (sessionEvent.anyOf as JSONSchema7[]) + .map((variant) => { + const typeSchema = variant.properties?.type as JSONSchema7; + const typeName = typeSchema?.const as string; + if (!typeName) throw new Error("Variant must have type.const"); + const baseName = toJavaClassName(typeName); + const dataSchema = variant.properties?.data as JSONSchema7 | undefined; + return { + typeName, + className: `${baseName}Event`, + dataSchema: dataSchema ?? null, + description: variant.description, + }; + }) + .filter((v) => !EXCLUDED_EVENT_TYPES.has(v.typeName)); +} + +async function generateSessionEvents(schemaPath: string): Promise { + console.log("\n📋 Generating session event classes..."); + const schemaContent = await fs.readFile(schemaPath, "utf-8"); + const schema = JSON.parse(schemaContent) as JSONSchema7; + + const variants = extractEventVariants(schema); + const packageName = "com.github.copilot.sdk.generated"; + const packageDir = `src/generated/java/com/github/copilot/sdk/generated`; + + // Generate base SessionEvent class + await generateSessionEventBaseClass(variants, packageName, packageDir); + + // Generate one class file per event variant + for (const variant of variants) { + await generateEventVariantClass(variant, packageName, packageDir); + } + + console.log(`✅ Generated ${variants.length + 1} session event files`); +} + +async function generateSessionEventBaseClass( + variants: EventVariant[], + packageName: string, + packageDir: string +): Promise { + const lines: string[] = []; + lines.push(COPYRIGHT); + lines.push(""); + lines.push(AUTO_GENERATED_HEADER); + lines.push(GENERATED_FROM_SESSION_EVENTS); + lines.push(""); + lines.push(`package ${packageName};`); + lines.push(""); + lines.push(`import com.fasterxml.jackson.annotation.JsonIgnoreProperties;`); + lines.push(`import com.fasterxml.jackson.annotation.JsonInclude;`); + lines.push(`import com.fasterxml.jackson.annotation.JsonProperty;`); + lines.push(`import com.fasterxml.jackson.annotation.JsonSubTypes;`); + lines.push(`import com.fasterxml.jackson.annotation.JsonTypeInfo;`); + lines.push(`import java.time.OffsetDateTime;`); + lines.push(`import java.util.UUID;`); + lines.push(`import javax.annotation.processing.Generated;`); + lines.push(""); + lines.push(`/**`); + lines.push(` * Base class for all generated session events.`); + lines.push(` *`); + lines.push(` * @since 1.0.0`); + lines.push(` */`); + lines.push(`@JsonIgnoreProperties(ignoreUnknown = true)`); + lines.push(`@JsonInclude(JsonInclude.Include.NON_NULL)`); + lines.push(`@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true, defaultImpl = UnknownSessionEvent.class)`); + lines.push(`@JsonSubTypes({`); + for (let i = 0; i < variants.length; i++) { + const v = variants[i]; + const comma = i < variants.length - 1 ? "," : ""; + lines.push(` @JsonSubTypes.Type(value = ${v.className}.class, name = "${v.typeName}")${comma}`); + } + lines.push(`})`); + lines.push(GENERATED_ANNOTATION); + + // Build the permits clause (all variant classes + UnknownSessionEvent last) + const allPermitted = [...variants.map((v) => v.className), "UnknownSessionEvent"]; + lines.push(`public abstract sealed class SessionEvent permits`); + for (let i = 0; i < allPermitted.length; i++) { + const comma = i < allPermitted.length - 1 ? "," : " {"; + lines.push(` ${allPermitted[i]}${comma}`); + } + lines.push(""); + lines.push(` /** Unique event identifier (UUID v4), generated when the event is emitted. */`); + lines.push(` @JsonProperty("id")`); + lines.push(` private UUID id;`); + lines.push(""); + lines.push(` /** ISO 8601 timestamp when the event was created. */`); + lines.push(` @JsonProperty("timestamp")`); + lines.push(` private OffsetDateTime timestamp;`); + lines.push(""); + lines.push(` /** ID of the chronologically preceding event in the session. Null for the first event. */`); + lines.push(` @JsonProperty("parentId")`); + lines.push(` private UUID parentId;`); + lines.push(""); + lines.push(` /** When true, the event is transient and not persisted to the session event log on disk. */`); + lines.push(` @JsonProperty("ephemeral")`); + lines.push(` private Boolean ephemeral;`); + lines.push(""); + lines.push(` /**`); + lines.push(` * Returns the event-type discriminator string (e.g., {@code "session.idle"}).`); + lines.push(` *`); + lines.push(` * @return the event type`); + lines.push(` */`); + lines.push(` public abstract String getType();`); + lines.push(""); + lines.push(` public UUID getId() { return id; }`); + lines.push(` public void setId(UUID id) { this.id = id; }`); + lines.push(""); + lines.push(` public OffsetDateTime getTimestamp() { return timestamp; }`); + lines.push(` public void setTimestamp(OffsetDateTime timestamp) { this.timestamp = timestamp; }`); + lines.push(""); + lines.push(` public UUID getParentId() { return parentId; }`); + lines.push(` public void setParentId(UUID parentId) { this.parentId = parentId; }`); + lines.push(""); + lines.push(` public Boolean getEphemeral() { return ephemeral; }`); + lines.push(` public void setEphemeral(Boolean ephemeral) { this.ephemeral = ephemeral; }`); + lines.push(`}`); + lines.push(""); + + await writeGeneratedFile(`${packageDir}/SessionEvent.java`, lines.join("\n")); + + // Also generate the UnknownSessionEvent fallback + await generateUnknownEventClass(packageName, packageDir); +} + +async function generateUnknownEventClass(packageName: string, packageDir: string): Promise { + const lines: string[] = []; + lines.push(COPYRIGHT); + lines.push(""); + lines.push(AUTO_GENERATED_HEADER); + lines.push(GENERATED_FROM_SESSION_EVENTS); + lines.push(""); + lines.push(`package ${packageName};`); + lines.push(""); + lines.push(`import com.fasterxml.jackson.annotation.JsonIgnoreProperties;`); + lines.push(`import com.fasterxml.jackson.annotation.JsonProperty;`); + lines.push(`import javax.annotation.processing.Generated;`); + lines.push(""); + lines.push(`/**`); + lines.push(` * Fallback for event types not yet known to this SDK version.`); + lines.push(` *

`); + lines.push(` * {@link #getType()} returns the original type string from the JSON payload,`); + lines.push(` * preserving forward compatibility with event types introduced by newer CLI versions.`); + lines.push(` *`); + lines.push(` * @since 1.0.0`); + lines.push(` */`); + lines.push(`@JsonIgnoreProperties(ignoreUnknown = true)`); + lines.push(GENERATED_ANNOTATION); + lines.push(`public final class UnknownSessionEvent extends SessionEvent {`); + lines.push(""); + lines.push(` @JsonProperty("type")`); + lines.push(` private String type = "unknown";`); + lines.push(""); + lines.push(` @Override`); + lines.push(` public String getType() { return type; }`); + lines.push(`}`); + lines.push(""); + + await writeGeneratedFile(`${packageDir}/UnknownSessionEvent.java`, lines.join("\n")); +} + +/** Render a nested type (enum or record) indented at the given level. */ +function renderNestedType(nested: JavaClassDef, indentLevel: number, nestedTypes: Map, allImports: Set): string[] { + const ind = " ".repeat(indentLevel); + const lines: string[] = []; + + if (nested.kind === "enum") { + lines.push(""); + if (nested.description) { + lines.push(`${ind}/** ${nested.description} */`); + } + lines.push(`${ind}public enum ${nested.name} {`); + for (let i = 0; i < (nested.values || []).length; i++) { + const v = nested.values![i]; + const comma = i < nested.values!.length - 1 ? "," : ";"; + lines.push(`${ind} /** The {@code ${v}} variant. */`); + lines.push(`${ind} ${toEnumConstant(v)}("${v}")${comma}`); + } + lines.push(""); + lines.push(`${ind} private final String value;`); + lines.push(`${ind} ${nested.name}(String value) { this.value = value; }`); + lines.push(`${ind} @com.fasterxml.jackson.annotation.JsonValue`); + lines.push(`${ind} public String getValue() { return value; }`); + lines.push(`${ind} @com.fasterxml.jackson.annotation.JsonCreator`); + lines.push(`${ind} public static ${nested.name} fromValue(String value) {`); + lines.push(`${ind} for (${nested.name} v : values()) {`); + lines.push(`${ind} if (v.value.equals(value)) return v;`); + lines.push(`${ind} }`); + lines.push(`${ind} throw new IllegalArgumentException("Unknown ${nested.name} value: " + value);`); + lines.push(`${ind} }`); + lines.push(`${ind}}`); + } else if (nested.kind === "class" && nested.schema?.properties) { + const localNestedTypes = new Map(); + const fields: { jsonName: string; javaName: string; javaType: string; description?: string }[] = []; + + for (const [propName, propSchema] of Object.entries(nested.schema.properties)) { + if (typeof propSchema !== "object") continue; + const prop = propSchema as JSONSchema7; + // Record components are always boxed (nullable by design). + const result = schemaTypeToJava(prop, false, nested.name, propName, localNestedTypes); + for (const imp of result.imports) allImports.add(imp); + fields.push({ jsonName: propName, javaName: toCamelCase(propName), javaType: result.javaType, description: prop.description }); + } + + lines.push(""); + if (nested.description) { + lines.push(`${ind}/** ${nested.description} */`); + } + lines.push(`${ind}@JsonIgnoreProperties(ignoreUnknown = true)`); + lines.push(`${ind}@JsonInclude(JsonInclude.Include.NON_NULL)`); + if (fields.length === 0) { + lines.push(`${ind}public record ${nested.name}() {`); + } else { + lines.push(`${ind}public record ${nested.name}(`); + for (let i = 0; i < fields.length; i++) { + const f = fields[i]; + const comma = i < fields.length - 1 ? "," : ""; + if (f.description) lines.push(`${ind} /** ${f.description} */`); + lines.push(`${ind} @JsonProperty("${f.jsonName}") ${f.javaType} ${f.javaName}${comma}`); + } + lines.push(`${ind}) {`); + } + // Render any further nested types inside this record + for (const [, localNested] of localNestedTypes) { + lines.push(...renderNestedType(localNested, indentLevel + 1, nestedTypes, allImports)); + } + if (lines[lines.length - 1] !== "") lines.push(""); + lines.pop(); // remove trailing blank before closing brace + lines.push(`${ind}}`); + } + + return lines; +} + +async function generateEventVariantClass( + variant: EventVariant, + packageName: string, + packageDir: string +): Promise { + const lines: string[] = []; + const allImports = new Set([ + "com.fasterxml.jackson.annotation.JsonIgnoreProperties", + "com.fasterxml.jackson.annotation.JsonProperty", + "com.fasterxml.jackson.annotation.JsonInclude", + "javax.annotation.processing.Generated", + ]); + const nestedTypes = new Map(); + + // Collect data record fields + interface FieldInfo { + jsonName: string; + javaName: string; + javaType: string; + description?: string; + } + + const dataFields: FieldInfo[] = []; + + if (variant.dataSchema?.properties) { + for (const [propName, propSchema] of Object.entries(variant.dataSchema.properties)) { + if (typeof propSchema !== "object") continue; + const prop = propSchema as JSONSchema7; + // Record components are always boxed (nullable by design). + const result = schemaTypeToJava(prop, false, `${variant.className}Data`, propName, nestedTypes); + for (const imp of result.imports) allImports.add(imp); + dataFields.push({ + jsonName: propName, + javaName: toCamelCase(propName), + javaType: result.javaType, + description: prop.description, + }); + } + } + + // Whether a data record should be emitted (always when dataSchema is present) + const hasDataSchema = variant.dataSchema !== null; + + // Build the file + lines.push(COPYRIGHT); + lines.push(""); + lines.push(AUTO_GENERATED_HEADER); + lines.push(GENERATED_FROM_SESSION_EVENTS); + lines.push(""); + lines.push(`package ${packageName};`); + lines.push(""); + + // Placeholder for imports + const importPlaceholderIdx = lines.length; + lines.push("__IMPORTS__"); + lines.push(""); + + if (variant.description) { + lines.push(`/**`); + lines.push(` * ${variant.description}`); + lines.push(` *`); + lines.push(` * @since 1.0.0`); + lines.push(` */`); + } else { + lines.push(`/**`); + lines.push(` * The {@code ${variant.typeName}} session event.`); + lines.push(` *`); + lines.push(` * @since 1.0.0`); + lines.push(` */`); + } + lines.push(`@JsonIgnoreProperties(ignoreUnknown = true)`); + lines.push(`@JsonInclude(JsonInclude.Include.NON_NULL)`); + lines.push(GENERATED_ANNOTATION); + lines.push(`public final class ${variant.className} extends SessionEvent {`); + lines.push(""); + lines.push(` @Override`); + lines.push(` public String getType() { return "${variant.typeName}"; }`); + + if (hasDataSchema) { + lines.push(""); + lines.push(` @JsonProperty("data")`); + lines.push(` private ${variant.className}Data data;`); + lines.push(""); + lines.push(` public ${variant.className}Data getData() { return data; }`); + lines.push(` public void setData(${variant.className}Data data) { this.data = data; }`); + lines.push(""); + // Generate data inner record + lines.push(` /** Data payload for {@link ${variant.className}}. */`); + lines.push(` @JsonIgnoreProperties(ignoreUnknown = true)`); + lines.push(` @JsonInclude(JsonInclude.Include.NON_NULL)`); + if (dataFields.length === 0) { + lines.push(` public record ${variant.className}Data() {`); + } else { + lines.push(` public record ${variant.className}Data(`); + for (let i = 0; i < dataFields.length; i++) { + const field = dataFields[i]; + const comma = i < dataFields.length - 1 ? "," : ""; + if (field.description) { + lines.push(` /** ${field.description} */`); + } + lines.push(` @JsonProperty("${field.jsonName}") ${field.javaType} ${field.javaName}${comma}`); + } + lines.push(` ) {`); + } + // Render nested types inside Data record + for (const [, nested] of nestedTypes) { + lines.push(...renderNestedType(nested, 2, nestedTypes, allImports)); + } + if (nestedTypes.size > 0 && lines[lines.length - 1] === "") lines.pop(); + lines.push(` }`); + } + + lines.push(`}`); + lines.push(""); + + // Replace import placeholder + const sortedImports = [...allImports].sort(); + const importLines = sortedImports.map((i) => `import ${i};`).join("\n"); + lines[importPlaceholderIdx] = importLines; + + await writeGeneratedFile(`${packageDir}/${variant.className}.java`, lines.join("\n")); +} + +// ── RPC types codegen ───────────────────────────────────────────────────────── + +interface RpcMethod { + rpcMethod: string; + params: JSONSchema7 | null; + result: JSONSchema7 | null; + stability?: string; +} + +function isRpcMethod(node: unknown): node is RpcMethod { + return typeof node === "object" && node !== null && "rpcMethod" in node; +} + +function collectRpcMethods(node: Record): [string, RpcMethod][] { + const results: [string, RpcMethod][] = []; + for (const [key, value] of Object.entries(node)) { + if (isRpcMethod(value)) { + results.push([key, value]); + } else if (typeof value === "object" && value !== null) { + results.push(...collectRpcMethods(value as Record)); + } + } + return results; +} + +/** Convert an RPC method name to a Java class name prefix (e.g., "models.list" -> "ModelsList") */ +function rpcMethodToClassName(rpcMethod: string): string { + return rpcMethod.split(/[._-]/).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(""); +} + +/** Generate a Java record for a JSON Schema object type. Returns the class content. */ +function generateRpcClass( + className: string, + schema: JSONSchema7, + _nestedTypes: Map, + _packageName: string, + visibility: "public" | "internal" = "public" +): { code: string; imports: Set } { + const imports = new Set(); + const localNestedTypes = new Map(); + const lines: string[] = []; + const visModifier = visibility === "public" ? "public " : ""; + + const properties = Object.entries(schema.properties || {}); + const fields = properties.flatMap(([propName, propSchema]) => { + if (typeof propSchema !== "object") return []; + const prop = propSchema as JSONSchema7; + // Record components are always boxed (nullable by design). + const result = schemaTypeToJava(prop, false, className, propName, localNestedTypes); + for (const imp of result.imports) imports.add(imp); + return [{ propName, javaName: toCamelCase(propName), javaType: result.javaType, description: prop.description }]; + }); + + lines.push(`@JsonInclude(JsonInclude.Include.NON_NULL)`); + lines.push(`@JsonIgnoreProperties(ignoreUnknown = true)`); + if (fields.length === 0) { + lines.push(`${visModifier}record ${className}() {`); + } else { + lines.push(`${visModifier}record ${className}(`); + for (let i = 0; i < fields.length; i++) { + const f = fields[i]; + const comma = i < fields.length - 1 ? "," : ""; + if (f.description) { + lines.push(` /** ${f.description} */`); + } + lines.push(` @JsonProperty("${f.propName}") ${f.javaType} ${f.javaName}${comma}`); + } + lines.push(`) {`); + } + + // Add nested types as nested records/enums inside this record + for (const [, nested] of localNestedTypes) { + lines.push(...renderNestedType(nested, 1, new Map(), imports)); + } + + if (localNestedTypes.size > 0 && lines[lines.length - 1] === "") lines.pop(); + lines.push(`}`); + + return { code: lines.join("\n"), imports }; +} + +async function generateRpcTypes(schemaPath: string): Promise { + console.log("\n🔌 Generating RPC types..."); + const schemaContent = await fs.readFile(schemaPath, "utf-8"); + const schema = JSON.parse(schemaContent) as Record & { + server?: Record; + session?: Record; + clientSession?: Record; + }; + + const packageName = "com.github.copilot.sdk.generated.rpc"; + const packageDir = `src/generated/java/com/github/copilot/sdk/generated/rpc`; + + // Collect all RPC methods from all sections + const sections: [string, Record][] = []; + if (schema.server) sections.push(["server", schema.server]); + if (schema.session) sections.push(["session", schema.session]); + if (schema.clientSession) sections.push(["clientSession", schema.clientSession]); + + const generatedClasses = new Map(); + const allFiles: string[] = []; + + for (const [, sectionNode] of sections) { + const methods = collectRpcMethods(sectionNode); + for (const [, method] of methods) { + const className = rpcMethodToClassName(method.rpcMethod); + + // Generate params class + if (method.params && typeof method.params === "object" && (method.params as JSONSchema7).properties) { + const paramsClassName = `${className}Params`; + if (!generatedClasses.has(paramsClassName)) { + generatedClasses.set(paramsClassName, true); + allFiles.push(await generateRpcDataClass(paramsClassName, method.params as JSONSchema7, packageName, packageDir, method.rpcMethod, "params")); + } + } + + // Generate result class + if (method.result && typeof method.result === "object" && (method.result as JSONSchema7).properties) { + const resultClassName = `${className}Result`; + if (!generatedClasses.has(resultClassName)) { + generatedClasses.set(resultClassName, true); + allFiles.push(await generateRpcDataClass(resultClassName, method.result as JSONSchema7, packageName, packageDir, method.rpcMethod, "result")); + } + } + } + } + + console.log(`✅ Generated ${allFiles.length} RPC type files`); +} + +async function generateRpcDataClass( + className: string, + schema: JSONSchema7, + packageName: string, + packageDir: string, + rpcMethod: string, + kind: "params" | "result" +): Promise { + const nestedTypes = new Map(); + const { code, imports } = generateRpcClass(className, schema, nestedTypes, packageName); + + const lines: string[] = []; + lines.push(COPYRIGHT); + lines.push(""); + lines.push(AUTO_GENERATED_HEADER); + lines.push(GENERATED_FROM_API); + lines.push(""); + lines.push(`package ${packageName};`); + lines.push(""); + + const allImports = new Set([ + "com.fasterxml.jackson.annotation.JsonIgnoreProperties", + "com.fasterxml.jackson.annotation.JsonProperty", + "com.fasterxml.jackson.annotation.JsonInclude", + "javax.annotation.processing.Generated", + ...imports, + ]); + const sortedImports = [...allImports].sort(); + for (const imp of sortedImports) { + lines.push(`import ${imp};`); + } + lines.push(""); + + if (schema.description) { + lines.push(`/**`); + lines.push(` * ${schema.description}`); + lines.push(` *`); + lines.push(` * @since 1.0.0`); + lines.push(` */`); + } else { + lines.push(`/**`); + lines.push(` * ${kind === "params" ? "Request parameters" : "Result"} for the {@code ${rpcMethod}} RPC method.`); + lines.push(` *`); + lines.push(` * @since 1.0.0`); + lines.push(` */`); + } + lines.push(GENERATED_ANNOTATION); + lines.push(code); + lines.push(""); + + await writeGeneratedFile(`${packageDir}/${className}.java`, lines.join("\n")); + return className; +} + +// ── RPC wrapper generation ─────────────────────────────────────────────────── + +/** A single RPC method node parsed from the schema */ +interface RpcMethodNode { + rpcMethod: string; + stability: string; + params: JSONSchema7 | null; + result: JSONSchema7 | null; +} + +/** Namespace tree node: holds direct methods and sub-namespace trees */ +interface NamespaceTree { + methods: Map; // leaf method name -> info + subspaces: Map; // sub-namespace name -> tree +} + +/** Build a namespace tree by recursively walking a schema section object */ +function buildNamespaceTree(node: Record): NamespaceTree { + const tree: NamespaceTree = { methods: new Map(), subspaces: new Map() }; + for (const [key, value] of Object.entries(node)) { + if (typeof value !== "object" || value === null) continue; + const obj = value as Record; + if ("rpcMethod" in obj) { + tree.methods.set(key, { + rpcMethod: String(obj.rpcMethod), + stability: String(obj.stability ?? "stable"), + params: (obj.params as JSONSchema7) ?? null, + result: (obj.result as JSONSchema7) ?? null, + }); + } else { + const child = buildNamespaceTree(obj); + // Only add non-empty sub-trees + if (child.methods.size > 0 || child.subspaces.size > 0) { + tree.subspaces.set(key, child); + } + } + } + return tree; +} + +/** + * Derive the Java class name for an API namespace class. + * e.g., prefix="Server", path=["mcp","config"] → "ServerMcpConfigApi" + */ +function apiClassName(prefix: string, path: string[]): string { + const parts = [prefix, ...path].map((p) => p.charAt(0).toUpperCase() + p.slice(1)); + return parts.join("") + "Api"; +} + +/** + * Derive the result class name for an RPC method. + * If the result schema has no properties we use Void; if no result schema we also use Void. + */ +function wrapperResultClassName(method: RpcMethodNode): string { + if ( + method.result && + typeof method.result === "object" && + method.result.properties && + Object.keys(method.result.properties).length > 0 + ) { + return rpcMethodToClassName(method.rpcMethod) + "Result"; + } + return "Void"; +} + +/** + * Return the params class name if the method has a params schema with properties + * other than sessionId (i.e. there are user-supplied parameters). + */ +function wrapperParamsClassName(method: RpcMethodNode): string | null { + if (!method.params || typeof method.params !== "object") return null; + const props = method.params.properties ?? {}; + const userProps = Object.keys(props).filter((k) => k !== "sessionId"); + if (userProps.length === 0) return null; + return rpcMethodToClassName(method.rpcMethod) + "Params"; +} + +/** True if the method's params schema contains a "sessionId" property */ +function methodHasSessionId(method: RpcMethodNode): boolean { + return !!method.params?.properties && "sessionId" in method.params.properties; +} + +/** + * Generate the Java source for a single method in a wrapper API class. + * Returns the Java source lines and whether an ObjectMapper is required. + */ +function generateApiMethod( + key: string, + method: RpcMethodNode, + isSession: boolean, + sessionIdExpr: string +): { lines: string[]; needsMapper: boolean } { + const resultClass = wrapperResultClassName(method); + const paramsClass = wrapperParamsClassName(method); + const hasSessionId = methodHasSessionId(method); + const hasExtraParams = paramsClass !== null; + let needsMapper = false; + + const lines: string[] = []; + + // Javadoc + const description = (method.params as JSONSchema7 | null)?.description + ?? (method.result as JSONSchema7 | null)?.description + ?? `Invokes {@code ${method.rpcMethod}}.`; + lines.push(` /**`); + lines.push(` * ${description}`); + if (method.stability === "experimental") { + lines.push(` *`); + lines.push(` * @apiNote This method is experimental and may change in a future version.`); + } + lines.push(` * @since 1.0.0`); + lines.push(` */`); + + // Signature + if (hasExtraParams) { + lines.push(` public CompletableFuture<${resultClass}> ${key}(${paramsClass} params) {`); + } else { + lines.push(` public CompletableFuture<${resultClass}> ${key}() {`); + } + + // Body + if (isSession) { + if (hasExtraParams) { + // Merge sessionId into the params using Jackson ObjectNode + needsMapper = true; + lines.push(` com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params);`); + lines.push(` _p.put("sessionId", ${sessionIdExpr});`); + lines.push(` return caller.invoke("${method.rpcMethod}", _p, ${resultClass}.class);`); + } else if (hasSessionId) { + lines.push(` return caller.invoke("${method.rpcMethod}", java.util.Map.of("sessionId", ${sessionIdExpr}), ${resultClass}.class);`); + } else { + lines.push(` return caller.invoke("${method.rpcMethod}", java.util.Map.of(), ${resultClass}.class);`); + } + } else { + // Server-side: pass params directly (or empty map if no params) + if (hasExtraParams) { + lines.push(` return caller.invoke("${method.rpcMethod}", params, ${resultClass}.class);`); + } else { + lines.push(` return caller.invoke("${method.rpcMethod}", java.util.Map.of(), ${resultClass}.class);`); + } + } + + lines.push(` }`); + lines.push(``); + + return { lines, needsMapper }; +} + +/** + * Generate a Java source file for a single namespace API class. + * Returns the generated class name and whether a mapper static field is needed. + */ +async function generateNamespaceApiFile( + prefix: string, + namespacePath: string[], + tree: NamespaceTree, + isSession: boolean, + packageName: string, + packageDir: string +): Promise { + const className = apiClassName(prefix, namespacePath); + const sessionIdExpr = "this.sessionId"; + + const classLines: string[] = []; + const allImports = new Set([ + "java.util.concurrent.CompletableFuture", + "javax.annotation.processing.Generated", + ]); + let needsMapper = false; + + // Generate sub-namespace fields + const subFields: string[] = []; + const subInits: string[] = []; + for (const [subKey, subTree] of tree.subspaces) { + const subClass = apiClassName(prefix, [...namespacePath, subKey]); + subFields.push(` /** API methods for the {@code ${[...namespacePath, subKey].join(".")}} sub-namespace. */`); + subFields.push(` public final ${subClass} ${subKey};`); + if (isSession) { + subInits.push(` this.${subKey} = new ${subClass}(caller, sessionId);`); + } else { + subInits.push(` this.${subKey} = new ${subClass}(caller);`); + } + // Recursively generate sub-namespace files + await generateNamespaceApiFile(prefix, [...namespacePath, subKey], subTree, isSession, packageName, packageDir); + } + + // Collect result/param imports and generate methods + const methodLines: string[] = []; + for (const [key, method] of tree.methods) { + const resultClass = wrapperResultClassName(method); + const paramsClass = wrapperParamsClassName(method); + if (resultClass !== "Void") allImports.add(`${packageName}.${resultClass}`); + if (paramsClass) allImports.add(`${packageName}.${paramsClass}`); + + const { lines, needsMapper: nm } = generateApiMethod(key, method, isSession, sessionIdExpr); + methodLines.push(...lines); + if (nm) needsMapper = true; + } + + // Build class body + const qualifiedNs = namespacePath.length > 0 ? namespacePath.join(".") : prefix.toLowerCase(); + classLines.push(COPYRIGHT); + classLines.push(``); + classLines.push(AUTO_GENERATED_HEADER); + classLines.push(GENERATED_FROM_API); + classLines.push(``); + classLines.push(`package ${packageName};`); + classLines.push(``); + + // Add imports (skip same-package imports) + const sortedImports = [...allImports].filter(imp => !imp.startsWith(packageName + ".")).sort(); + for (const imp of sortedImports) { + classLines.push(`import ${imp};`); + } + classLines.push(``); + + // Javadoc for class + classLines.push(`/**`); + classLines.push(` * API methods for the {@code ${qualifiedNs}} namespace.`); + classLines.push(` *`); + classLines.push(` * @since 1.0.0`); + classLines.push(` */`); + classLines.push(GENERATED_ANNOTATION); + classLines.push(`public final class ${className} {`); + classLines.push(``); + if (needsMapper) { + classLines.push(` private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = RpcMapper.INSTANCE;`); + classLines.push(``); + } + classLines.push(` private final RpcCaller caller;`); + if (isSession) { + classLines.push(` private final String sessionId;`); + } + + // Sub-namespace fields + if (subFields.length > 0) { + classLines.push(``); + classLines.push(...subFields); + } + + // Constructor + classLines.push(``); + if (isSession) { + classLines.push(` /** @param caller the RPC transport function */`); + classLines.push(` ${className}(RpcCaller caller, String sessionId) {`); + classLines.push(` this.caller = caller;`); + classLines.push(` this.sessionId = sessionId;`); + } else { + classLines.push(` /** @param caller the RPC transport function */`); + classLines.push(` ${className}(RpcCaller caller) {`); + classLines.push(` this.caller = caller;`); + } + for (const init of subInits) { + classLines.push(init); + } + classLines.push(` }`); + classLines.push(``); + + // Methods + classLines.push(...methodLines); + + classLines.push(`}`); + classLines.push(``); + + await writeGeneratedFile(`${packageDir}/${className}.java`, classLines.join("\n")); + return className; +} + +/** + * Generate ServerRpc.java or SessionRpc.java — the top-level wrapper class. + */ +async function generateRpcRootFile( + sectionName: string, // "server" | "session" + tree: NamespaceTree, + isSession: boolean, + packageName: string, + packageDir: string +): Promise { + const prefix = sectionName === "server" ? "Server" : "Session"; + const rootClassName = prefix + "Rpc"; + const sessionIdExpr = "this.sessionId"; + + const classLines: string[] = []; + const allImports = new Set([ + "java.util.concurrent.CompletableFuture", + "javax.annotation.processing.Generated", + ]); + let needsMapper = false; + + // Sub-namespace fields and init lines + const subFields: string[] = []; + const subInits: string[] = []; + for (const [nsKey, nsTree] of tree.subspaces) { + const nsClass = apiClassName(prefix, [nsKey]); + subFields.push(` /** API methods for the {@code ${nsKey}} namespace. */`); + subFields.push(` public final ${nsClass} ${nsKey};`); + if (isSession) { + subInits.push(` this.${nsKey} = new ${nsClass}(caller, sessionId);`); + } else { + subInits.push(` this.${nsKey} = new ${nsClass}(caller);`); + } + // Generate the namespace API class file (recursively) + await generateNamespaceApiFile(prefix, [nsKey], nsTree, isSession, packageName, packageDir); + } + + // Collect result/param imports and generate top-level method bodies + const methodLines: string[] = []; + for (const [key, method] of tree.methods) { + const resultClass = wrapperResultClassName(method); + const paramsClass = wrapperParamsClassName(method); + if (resultClass !== "Void") allImports.add(`${packageName}.${resultClass}`); + if (paramsClass) allImports.add(`${packageName}.${paramsClass}`); + + const { lines, needsMapper: nm } = generateApiMethod(key, method, isSession, sessionIdExpr); + methodLines.push(...lines); + if (nm) needsMapper = true; + } + + // Build file content + classLines.push(COPYRIGHT); + classLines.push(``); + classLines.push(AUTO_GENERATED_HEADER); + classLines.push(GENERATED_FROM_API); + classLines.push(``); + classLines.push(`package ${packageName};`); + classLines.push(``); + + const sortedImports = [...allImports].filter(imp => !imp.startsWith(packageName + ".")).sort(); + for (const imp of sortedImports) { + classLines.push(`import ${imp};`); + } + classLines.push(``); + + classLines.push(`/**`); + if (isSession) { + classLines.push(` * Typed client for session-scoped RPC methods.`); + classLines.push(` *

`); + classLines.push(` * Provides strongly-typed access to all session-level API namespaces.`); + classLines.push(` * The {@code sessionId} is injected automatically into every call.`); + classLines.push(` *

`); + classLines.push(` * Obtain an instance by calling {@code new SessionRpc(caller, sessionId)}.`); + } else { + classLines.push(` * Typed client for server-level RPC methods.`); + classLines.push(` *

`); + classLines.push(` * Provides strongly-typed access to all server-level API namespaces.`); + classLines.push(` *

`); + classLines.push(` * Obtain an instance by calling {@code new ServerRpc(caller)}.`); + } + classLines.push(` *`); + classLines.push(` * @since 1.0.0`); + classLines.push(` */`); + classLines.push(GENERATED_ANNOTATION); + classLines.push(`public final class ${rootClassName} {`); + classLines.push(``); + if (needsMapper) { + classLines.push(` private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = RpcMapper.INSTANCE;`); + classLines.push(``); + } + classLines.push(` private final RpcCaller caller;`); + if (isSession) { + classLines.push(` private final String sessionId;`); + } + if (subFields.length > 0) { + classLines.push(``); + classLines.push(...subFields); + } + classLines.push(``); + + // Constructor + if (isSession) { + classLines.push(` /**`); + classLines.push(` * Creates a new session RPC client.`); + classLines.push(` *`); + classLines.push(` * @param caller the RPC transport function (e.g., {@code jsonRpcClient::invoke})`); + classLines.push(` * @param sessionId the session ID to inject into every request`); + classLines.push(` */`); + classLines.push(` public ${rootClassName}(RpcCaller caller, String sessionId) {`); + classLines.push(` this.caller = caller;`); + classLines.push(` this.sessionId = sessionId;`); + } else { + classLines.push(` /**`); + classLines.push(` * Creates a new server RPC client.`); + classLines.push(` *`); + classLines.push(` * @param caller the RPC transport function (e.g., {@code jsonRpcClient::invoke})`); + classLines.push(` */`); + classLines.push(` public ${rootClassName}(RpcCaller caller) {`); + classLines.push(` this.caller = caller;`); + } + for (const init of subInits) { + classLines.push(init); + } + classLines.push(` }`); + classLines.push(``); + + // Top-level methods + classLines.push(...methodLines); + + classLines.push(`}`); + classLines.push(``); + + await writeGeneratedFile(`${packageDir}/${rootClassName}.java`, classLines.join("\n")); +} + +/** Generate the RpcCaller functional interface */ +async function generateRpcCallerInterface(packageName: string, packageDir: string): Promise { + const lines: string[] = []; + lines.push(COPYRIGHT); + lines.push(``); + lines.push(AUTO_GENERATED_HEADER); + lines.push(GENERATED_FROM_API); + lines.push(``); + lines.push(`package ${packageName};`); + lines.push(``); + lines.push(`import java.util.concurrent.CompletableFuture;`); + lines.push(`import javax.annotation.processing.Generated;`); + lines.push(``); + lines.push(`/**`); + lines.push(` * Interface for invoking JSON-RPC methods with typed responses.`); + lines.push(` *

`); + lines.push(` * Implementations delegate to the underlying transport layer`); + lines.push(` * (e.g., a {@code JsonRpcClient} instance). Use a method reference:`); + lines.push(` *

{@code`);
+    lines.push(` * RpcCaller caller = jsonRpcClient::invoke;`);
+    lines.push(` * }
`); + lines.push(` * Note: because the {@code invoke} method has a type parameter, this interface cannot`); + lines.push(` * be implemented using a lambda expression — use a method reference or anonymous class.`); + lines.push(` *`); + lines.push(` * @since 1.0.0`); + lines.push(` */`); + lines.push(GENERATED_ANNOTATION); + lines.push(`public interface RpcCaller {`); + lines.push(``); + lines.push(` /**`); + lines.push(` * Invokes a JSON-RPC method and returns a future for the typed response.`); + lines.push(` *`); + lines.push(` * @param the expected response type`); + lines.push(` * @param method the JSON-RPC method name`); + lines.push(` * @param params the request parameters (may be a {@code Map}, DTO record, or {@code JsonNode})`); + lines.push(` * @param resultType the {@link Class} of the expected response type`); + lines.push(` * @return a {@link CompletableFuture} that completes with the deserialized result`); + lines.push(` */`); + lines.push(` CompletableFuture invoke(String method, Object params, Class resultType);`); + lines.push(`}`); + lines.push(``); + + await writeGeneratedFile(`${packageDir}/RpcCaller.java`, lines.join("\n")); +} + +/** + * Generate RpcMapper.java — a package-private holder for the shared ObjectMapper used + * when merging sessionId into session API call params. All session API classes that + * need an ObjectMapper reference this single instance instead of instantiating their own. + */ +async function generateRpcMapperClass(packageName: string, packageDir: string): Promise { + const lines: string[] = []; + lines.push(COPYRIGHT); + lines.push(``); + lines.push(AUTO_GENERATED_HEADER); + lines.push(GENERATED_FROM_API); + lines.push(``); + lines.push(`package ${packageName};`); + lines.push(``); + lines.push(`import javax.annotation.processing.Generated;`); + lines.push(``); + lines.push(`/**`); + lines.push(` * Package-private holder for the shared {@link com.fasterxml.jackson.databind.ObjectMapper}`); + lines.push(` * used by session API classes when merging {@code sessionId} into call parameters.`); + lines.push(` *

`); + lines.push(` * {@link com.fasterxml.jackson.databind.ObjectMapper} is thread-safe and expensive to`); + lines.push(` * instantiate, so a single shared instance is used across all generated API classes.`); + lines.push(` *`); + lines.push(` * @since 1.0.0`); + lines.push(` */`); + lines.push(GENERATED_ANNOTATION); + lines.push(`final class RpcMapper {`); + lines.push(``); + lines.push(` static final com.fasterxml.jackson.databind.ObjectMapper INSTANCE =`); + lines.push(` new com.fasterxml.jackson.databind.ObjectMapper();`); + lines.push(``); + lines.push(` private RpcMapper() {}`); + lines.push(`}`); + lines.push(``); + + await writeGeneratedFile(`${packageDir}/RpcMapper.java`, lines.join("\n")); +} + +/** Main entry point for RPC wrapper generation */ +async function generateRpcWrappers(schemaPath: string): Promise { + console.log("\n🔧 Generating RPC wrapper classes..."); + + const schemaContent = await fs.readFile(schemaPath, "utf-8"); + const schema = JSON.parse(schemaContent) as { + server?: Record; + session?: Record; + clientSession?: Record; + }; + + const packageName = "com.github.copilot.sdk.generated.rpc"; + const packageDir = `src/generated/java/com/github/copilot/sdk/generated/rpc`; + + // RpcCaller interface and shared ObjectMapper holder + await generateRpcCallerInterface(packageName, packageDir); + await generateRpcMapperClass(packageName, packageDir); + + // Server-side wrappers + if (schema.server) { + const serverTree = buildNamespaceTree(schema.server); + await generateRpcRootFile("server", serverTree, false, packageName, packageDir); + } + + // Session-side wrappers + if (schema.session) { + const sessionTree = buildNamespaceTree(schema.session); + await generateRpcRootFile("session", sessionTree, true, packageName, packageDir); + } + + console.log(`✅ RPC wrapper classes generated`); +} + +// ── Main entry point ────────────────────────────────────────────────────────── + +async function main(): Promise { + console.log("🚀 Java SDK code generator"); + console.log("============================"); + + const sessionEventsSchemaPath = await getSessionEventsSchemaPath(); + console.log(`📄 Session events schema: ${sessionEventsSchemaPath}`); + const apiSchemaPath = await getApiSchemaPath(); + console.log(`📄 API schema: ${apiSchemaPath}`); + + await generateSessionEvents(sessionEventsSchemaPath); + await generateRpcTypes(apiSchemaPath); + await generateRpcWrappers(apiSchemaPath); + + console.log("\n✅ Java code generation complete!"); +} + +main().catch((err) => { + console.error("❌ Code generation failed:", err); + process.exit(1); +}); diff --git a/scripts/codegen/package-lock.json b/scripts/codegen/package-lock.json new file mode 100644 index 000000000..4a3705f36 --- /dev/null +++ b/scripts/codegen/package-lock.json @@ -0,0 +1,645 @@ +{ + "name": "copilot-sdk-java-codegen", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "copilot-sdk-java-codegen", + "dependencies": { + "@github/copilot": "1.0.24", + "json-schema": "^0.4.0", + "tsx": "^4.20.6" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@github/copilot": { + "version": "1.0.24", + "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.24.tgz", + "integrity": "sha512-/nZ2GwhaGq0HeI3W+6LE0JGw25/bipC6tYVa+oQ5tIvAafBazuNt10CXkeaor+u9oBWLZtPbdTyAzE2tjy9NpQ==", + "license": "SEE LICENSE IN LICENSE.md", + "bin": { + "copilot": "npm-loader.js" + }, + "optionalDependencies": { + "@github/copilot-darwin-arm64": "1.0.24", + "@github/copilot-darwin-x64": "1.0.24", + "@github/copilot-linux-arm64": "1.0.24", + "@github/copilot-linux-x64": "1.0.24", + "@github/copilot-win32-arm64": "1.0.24", + "@github/copilot-win32-x64": "1.0.24" + } + }, + "node_modules/@github/copilot-darwin-arm64": { + "version": "1.0.24", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.24.tgz", + "integrity": "sha512-lejn6KV+09rZEICX3nRx9a58DQFQ2kK3NJ3EICfVLngUCWIUmwn1BLezjeTQc9YNasHltA1hulvfsWqX+VjlMw==", + "cpu": [ + "arm64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "darwin" + ], + "bin": { + "copilot-darwin-arm64": "copilot" + } + }, + "node_modules/@github/copilot-darwin-x64": { + "version": "1.0.24", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.24.tgz", + "integrity": "sha512-r2F3keTvr4Bunz3V+waRAvsHgqsVQGyIZFBebsNPWxBX1eh3IXgtBqxCR7vXTFyZonQ8VaiJH3YYEfAhyKsk9g==", + "cpu": [ + "x64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "darwin" + ], + "bin": { + "copilot-darwin-x64": "copilot" + } + }, + "node_modules/@github/copilot-linux-arm64": { + "version": "1.0.24", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.24.tgz", + "integrity": "sha512-B3oANXKKKLhnKYozXa/W+DxfCQAHJCs0QKR5rBwNrwJbf656twNgALSxWTSJk+1rEP6MrHCswUAcwjwZL7Q+FQ==", + "cpu": [ + "arm64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "linux" + ], + "bin": { + "copilot-linux-arm64": "copilot" + } + }, + "node_modules/@github/copilot-linux-x64": { + "version": "1.0.24", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.24.tgz", + "integrity": "sha512-NGTldizY54B+4Sfhu/GWoEQNMwqqUNgMwbSgBshFv+Hqy1EwuvNWKVov1Y0Vzhp4qAHc6ZxBk/OPIW8Ato9FUg==", + "cpu": [ + "x64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "linux" + ], + "bin": { + "copilot-linux-x64": "copilot" + } + }, + "node_modules/@github/copilot-win32-arm64": { + "version": "1.0.24", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.24.tgz", + "integrity": "sha512-/pd/kgef7/HIIg1SQq4q8fext39pDSC44jHB10KkhfgG1WaDFhQbc/aSSMQfxeldkRbQh6VANp8WtGQdwtMCBA==", + "cpu": [ + "arm64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "win32" + ], + "bin": { + "copilot-win32-arm64": "copilot.exe" + } + }, + "node_modules/@github/copilot-win32-x64": { + "version": "1.0.24", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.24.tgz", + "integrity": "sha512-RDvOiSvyEJwELqErwANJTrdRuMIHkwPE4QK7Le7WsmaSKxiuS4H1Pa8Yxnd2FWrMsCHEbase23GJlymbnGYLXQ==", + "cpu": [ + "x64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "win32" + ], + "bin": { + "copilot-win32-x64": "copilot.exe" + } + }, + "node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.7", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz", + "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==", + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + } + } +} diff --git a/scripts/codegen/package.json b/scripts/codegen/package.json new file mode 100644 index 000000000..38dd5fc1f --- /dev/null +++ b/scripts/codegen/package.json @@ -0,0 +1,14 @@ +{ + "name": "copilot-sdk-java-codegen", + "private": true, + "type": "module", + "scripts": { + "generate": "tsx java.ts", + "generate:java": "tsx java.ts" + }, + "dependencies": { + "@github/copilot": "1.0.24", + "json-schema": "^0.4.0", + "tsx": "^4.20.6" + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/AbortEvent.java b/src/generated/java/com/github/copilot/sdk/generated/AbortEvent.java new file mode 100644 index 000000000..d236f04f0 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/AbortEvent.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code abort} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class AbortEvent extends SessionEvent { + + @Override + public String getType() { return "abort"; } + + @JsonProperty("data") + private AbortEventData data; + + public AbortEventData getData() { return data; } + public void setData(AbortEventData data) { this.data = data; } + + /** Data payload for {@link AbortEvent}. */ + @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 + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/AssistantIntentEvent.java b/src/generated/java/com/github/copilot/sdk/generated/AssistantIntentEvent.java new file mode 100644 index 000000000..a1c22edfb --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/AssistantIntentEvent.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code assistant.intent} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class AssistantIntentEvent extends SessionEvent { + + @Override + public String getType() { return "assistant.intent"; } + + @JsonProperty("data") + private AssistantIntentEventData data; + + public AssistantIntentEventData getData() { return data; } + public void setData(AssistantIntentEventData data) { this.data = data; } + + /** Data payload for {@link AssistantIntentEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record AssistantIntentEventData( + /** Short description of what the agent is currently doing or planning to do */ + @JsonProperty("intent") String intent + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/AssistantMessageDeltaEvent.java b/src/generated/java/com/github/copilot/sdk/generated/AssistantMessageDeltaEvent.java new file mode 100644 index 000000000..128608a1e --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/AssistantMessageDeltaEvent.java @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code assistant.message_delta} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class AssistantMessageDeltaEvent extends SessionEvent { + + @Override + public String getType() { return "assistant.message_delta"; } + + @JsonProperty("data") + private AssistantMessageDeltaEventData data; + + public AssistantMessageDeltaEventData getData() { return data; } + public void setData(AssistantMessageDeltaEventData data) { this.data = data; } + + /** Data payload for {@link AssistantMessageDeltaEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record AssistantMessageDeltaEventData( + /** Message ID this delta belongs to, matching the corresponding assistant.message event */ + @JsonProperty("messageId") String messageId, + /** Incremental text chunk to append to the message content */ + @JsonProperty("deltaContent") String deltaContent, + /** Tool call ID of the parent tool invocation when this event originates from a sub-agent */ + @JsonProperty("parentToolCallId") String parentToolCallId + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/AssistantMessageEvent.java b/src/generated/java/com/github/copilot/sdk/generated/AssistantMessageEvent.java new file mode 100644 index 000000000..78ccbf42f --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/AssistantMessageEvent.java @@ -0,0 +1,104 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The {@code assistant.message} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class AssistantMessageEvent extends SessionEvent { + + @Override + public String getType() { return "assistant.message"; } + + @JsonProperty("data") + private AssistantMessageEventData data; + + public AssistantMessageEventData getData() { return data; } + public void setData(AssistantMessageEventData data) { this.data = data; } + + /** Data payload for {@link AssistantMessageEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record AssistantMessageEventData( + /** Unique identifier for this assistant message */ + @JsonProperty("messageId") String messageId, + /** The assistant's text response content */ + @JsonProperty("content") String content, + /** Tool invocations requested by the assistant in this message */ + @JsonProperty("toolRequests") List toolRequests, + /** Opaque/encrypted extended thinking data from Anthropic models. Session-bound and stripped on resume. */ + @JsonProperty("reasoningOpaque") String reasoningOpaque, + /** Readable reasoning text from the model's extended thinking */ + @JsonProperty("reasoningText") String reasoningText, + /** Encrypted reasoning content from OpenAI models. Session-bound and stripped on resume. */ + @JsonProperty("encryptedContent") String encryptedContent, + /** Generation phase for phased-output models (e.g., thinking vs. response phases) */ + @JsonProperty("phase") String phase, + /** Actual output token count from the API response (completion_tokens), used for accurate token accounting */ + @JsonProperty("outputTokens") Double outputTokens, + /** CAPI interaction ID for correlating this message with upstream telemetry */ + @JsonProperty("interactionId") String interactionId, + /** GitHub request tracing ID (x-github-request-id header) for correlating with server-side logs */ + @JsonProperty("requestId") String requestId, + /** Tool call ID of the parent tool invocation when this event originates from a sub-agent */ + @JsonProperty("parentToolCallId") String parentToolCallId + ) { + + /** A tool invocation request from the assistant */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record AssistantMessageEventDataToolRequestsItem( + /** Unique identifier for this tool call */ + @JsonProperty("toolCallId") String toolCallId, + /** Name of the tool being invoked */ + @JsonProperty("name") String name, + /** Arguments to pass to the tool, format depends on the tool */ + @JsonProperty("arguments") Object arguments, + /** Tool call type: "function" for standard tool calls, "custom" for grammar-based tool calls. Defaults to "function" when absent. */ + @JsonProperty("type") AssistantMessageEventDataToolRequestsItemType type, + /** Human-readable display title for the tool */ + @JsonProperty("toolTitle") String toolTitle, + /** Name of the MCP server hosting this tool, when the tool is an MCP tool */ + @JsonProperty("mcpServerName") String mcpServerName, + /** Resolved intention summary describing what this specific call does */ + @JsonProperty("intentionSummary") String intentionSummary + ) { + + /** Tool call type: "function" for standard tool calls, "custom" for grammar-based tool calls. Defaults to "function" when absent. */ + public enum AssistantMessageEventDataToolRequestsItemType { + /** The {@code function} variant. */ + FUNCTION("function"), + /** The {@code custom} variant. */ + CUSTOM("custom"); + + private final String value; + AssistantMessageEventDataToolRequestsItemType(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static AssistantMessageEventDataToolRequestsItemType fromValue(String value) { + for (AssistantMessageEventDataToolRequestsItemType v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown AssistantMessageEventDataToolRequestsItemType value: " + value); + } + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/AssistantReasoningDeltaEvent.java b/src/generated/java/com/github/copilot/sdk/generated/AssistantReasoningDeltaEvent.java new file mode 100644 index 000000000..7c11ad59e --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/AssistantReasoningDeltaEvent.java @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code assistant.reasoning_delta} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class AssistantReasoningDeltaEvent extends SessionEvent { + + @Override + public String getType() { return "assistant.reasoning_delta"; } + + @JsonProperty("data") + private AssistantReasoningDeltaEventData data; + + public AssistantReasoningDeltaEventData getData() { return data; } + public void setData(AssistantReasoningDeltaEventData data) { this.data = data; } + + /** Data payload for {@link AssistantReasoningDeltaEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record AssistantReasoningDeltaEventData( + /** Reasoning block ID this delta belongs to, matching the corresponding assistant.reasoning event */ + @JsonProperty("reasoningId") String reasoningId, + /** Incremental text chunk to append to the reasoning content */ + @JsonProperty("deltaContent") String deltaContent + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/AssistantReasoningEvent.java b/src/generated/java/com/github/copilot/sdk/generated/AssistantReasoningEvent.java new file mode 100644 index 000000000..292b191b1 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/AssistantReasoningEvent.java @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code assistant.reasoning} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class AssistantReasoningEvent extends SessionEvent { + + @Override + public String getType() { return "assistant.reasoning"; } + + @JsonProperty("data") + private AssistantReasoningEventData data; + + public AssistantReasoningEventData getData() { return data; } + public void setData(AssistantReasoningEventData data) { this.data = data; } + + /** Data payload for {@link AssistantReasoningEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record AssistantReasoningEventData( + /** Unique identifier for this reasoning block */ + @JsonProperty("reasoningId") String reasoningId, + /** The complete extended thinking text from the model */ + @JsonProperty("content") String content + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/AssistantStreamingDeltaEvent.java b/src/generated/java/com/github/copilot/sdk/generated/AssistantStreamingDeltaEvent.java new file mode 100644 index 000000000..71ec8f488 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/AssistantStreamingDeltaEvent.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code assistant.streaming_delta} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class AssistantStreamingDeltaEvent extends SessionEvent { + + @Override + public String getType() { return "assistant.streaming_delta"; } + + @JsonProperty("data") + private AssistantStreamingDeltaEventData data; + + public AssistantStreamingDeltaEventData getData() { return data; } + public void setData(AssistantStreamingDeltaEventData data) { this.data = data; } + + /** Data payload for {@link AssistantStreamingDeltaEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record AssistantStreamingDeltaEventData( + /** Cumulative total bytes received from the streaming response so far */ + @JsonProperty("totalResponseSizeBytes") Double totalResponseSizeBytes + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/AssistantTurnEndEvent.java b/src/generated/java/com/github/copilot/sdk/generated/AssistantTurnEndEvent.java new file mode 100644 index 000000000..a8e0b1652 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/AssistantTurnEndEvent.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code assistant.turn_end} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class AssistantTurnEndEvent extends SessionEvent { + + @Override + public String getType() { return "assistant.turn_end"; } + + @JsonProperty("data") + private AssistantTurnEndEventData data; + + public AssistantTurnEndEventData getData() { return data; } + public void setData(AssistantTurnEndEventData data) { this.data = data; } + + /** Data payload for {@link AssistantTurnEndEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record AssistantTurnEndEventData( + /** Identifier of the turn that has ended, matching the corresponding assistant.turn_start event */ + @JsonProperty("turnId") String turnId + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/AssistantTurnStartEvent.java b/src/generated/java/com/github/copilot/sdk/generated/AssistantTurnStartEvent.java new file mode 100644 index 000000000..921623801 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/AssistantTurnStartEvent.java @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code assistant.turn_start} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class AssistantTurnStartEvent extends SessionEvent { + + @Override + public String getType() { return "assistant.turn_start"; } + + @JsonProperty("data") + private AssistantTurnStartEventData data; + + public AssistantTurnStartEventData getData() { return data; } + public void setData(AssistantTurnStartEventData data) { this.data = data; } + + /** Data payload for {@link AssistantTurnStartEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record AssistantTurnStartEventData( + /** Identifier for this turn within the agentic loop, typically a stringified turn number */ + @JsonProperty("turnId") String turnId, + /** CAPI interaction ID for correlating this turn with upstream telemetry */ + @JsonProperty("interactionId") String interactionId + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/AssistantUsageEvent.java b/src/generated/java/com/github/copilot/sdk/generated/AssistantUsageEvent.java new file mode 100644 index 000000000..65f47bfad --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/AssistantUsageEvent.java @@ -0,0 +1,125 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.OffsetDateTime; +import java.util.List; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The {@code assistant.usage} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class AssistantUsageEvent extends SessionEvent { + + @Override + public String getType() { return "assistant.usage"; } + + @JsonProperty("data") + private AssistantUsageEventData data; + + public AssistantUsageEventData getData() { return data; } + public void setData(AssistantUsageEventData data) { this.data = data; } + + /** Data payload for {@link AssistantUsageEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record AssistantUsageEventData( + /** Model identifier used for this API call */ + @JsonProperty("model") String model, + /** Number of input tokens consumed */ + @JsonProperty("inputTokens") Double inputTokens, + /** Number of output tokens produced */ + @JsonProperty("outputTokens") Double outputTokens, + /** Number of tokens read from prompt cache */ + @JsonProperty("cacheReadTokens") Double cacheReadTokens, + /** Number of tokens written to prompt cache */ + @JsonProperty("cacheWriteTokens") Double cacheWriteTokens, + /** Number of output tokens used for reasoning (e.g., chain-of-thought) */ + @JsonProperty("reasoningTokens") Double reasoningTokens, + /** Model multiplier cost for billing purposes */ + @JsonProperty("cost") Double cost, + /** Duration of the API call in milliseconds */ + @JsonProperty("duration") Double duration, + /** Time to first token in milliseconds. Only available for streaming requests */ + @JsonProperty("ttftMs") Double ttftMs, + /** Average inter-token latency in milliseconds. Only available for streaming requests */ + @JsonProperty("interTokenLatencyMs") Double interTokenLatencyMs, + /** What initiated this API call (e.g., "sub-agent", "mcp-sampling"); absent for user-initiated calls */ + @JsonProperty("initiator") String initiator, + /** Completion ID from the model provider (e.g., chatcmpl-abc123) */ + @JsonProperty("apiCallId") String apiCallId, + /** GitHub request tracing ID (x-github-request-id header) for server-side log correlation */ + @JsonProperty("providerCallId") String providerCallId, + /** Parent tool call ID when this usage originates from a sub-agent */ + @JsonProperty("parentToolCallId") String parentToolCallId, + /** Per-quota resource usage snapshots, keyed by quota identifier */ + @JsonProperty("quotaSnapshots") Map quotaSnapshots, + /** Per-request cost and usage data from the CAPI copilot_usage response field */ + @JsonProperty("copilotUsage") AssistantUsageEventDataCopilotUsage copilotUsage, + /** Reasoning effort level used for model calls, if applicable (e.g. "low", "medium", "high", "xhigh") */ + @JsonProperty("reasoningEffort") String reasoningEffort + ) { + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record AssistantUsageEventDataQuotaSnapshotsValue( + /** Whether the user has an unlimited usage entitlement */ + @JsonProperty("isUnlimitedEntitlement") Boolean isUnlimitedEntitlement, + /** Total requests allowed by the entitlement */ + @JsonProperty("entitlementRequests") Double entitlementRequests, + /** Number of requests already consumed */ + @JsonProperty("usedRequests") Double usedRequests, + /** Whether usage is still permitted after quota exhaustion */ + @JsonProperty("usageAllowedWithExhaustedQuota") Boolean usageAllowedWithExhaustedQuota, + /** Number of requests over the entitlement limit */ + @JsonProperty("overage") Double overage, + /** Whether overage is allowed when quota is exhausted */ + @JsonProperty("overageAllowedWithExhaustedQuota") Boolean overageAllowedWithExhaustedQuota, + /** Percentage of quota remaining (0.0 to 1.0) */ + @JsonProperty("remainingPercentage") Double remainingPercentage, + /** Date when the quota resets */ + @JsonProperty("resetDate") OffsetDateTime resetDate + ) { + } + + /** Per-request cost and usage data from the CAPI copilot_usage response field */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record AssistantUsageEventDataCopilotUsage( + /** Itemized token usage breakdown */ + @JsonProperty("tokenDetails") List tokenDetails, + /** Total cost in nano-AIU (AI Units) for this request */ + @JsonProperty("totalNanoAiu") Double totalNanoAiu + ) { + + /** Token usage detail for a single billing category */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record AssistantUsageEventDataCopilotUsageTokenDetailsItem( + /** Number of tokens in this billing batch */ + @JsonProperty("batchSize") Double batchSize, + /** Cost per batch of tokens */ + @JsonProperty("costPerBatch") Double costPerBatch, + /** Total token count for this entry */ + @JsonProperty("tokenCount") Double tokenCount, + /** Token category (e.g., "input", "output") */ + @JsonProperty("tokenType") String tokenType + ) { + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/CapabilitiesChangedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/CapabilitiesChangedEvent.java new file mode 100644 index 000000000..fbf14f8ec --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/CapabilitiesChangedEvent.java @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code capabilities.changed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class CapabilitiesChangedEvent extends SessionEvent { + + @Override + public String getType() { return "capabilities.changed"; } + + @JsonProperty("data") + private CapabilitiesChangedEventData data; + + public CapabilitiesChangedEventData getData() { return data; } + public void setData(CapabilitiesChangedEventData data) { this.data = data; } + + /** Data payload for {@link CapabilitiesChangedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record CapabilitiesChangedEventData( + /** UI capability changes */ + @JsonProperty("ui") CapabilitiesChangedEventDataUi ui + ) { + + /** UI capability changes */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record CapabilitiesChangedEventDataUi( + /** Whether elicitation is now supported */ + @JsonProperty("elicitation") Boolean elicitation + ) { + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/CommandCompletedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/CommandCompletedEvent.java new file mode 100644 index 000000000..d2075f09d --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/CommandCompletedEvent.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code command.completed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class CommandCompletedEvent extends SessionEvent { + + @Override + public String getType() { return "command.completed"; } + + @JsonProperty("data") + private CommandCompletedEventData data; + + public CommandCompletedEventData getData() { return data; } + public void setData(CommandCompletedEventData data) { this.data = data; } + + /** Data payload for {@link CommandCompletedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record CommandCompletedEventData( + /** Request ID of the resolved command request; clients should dismiss any UI for this request */ + @JsonProperty("requestId") String requestId + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/CommandExecuteEvent.java b/src/generated/java/com/github/copilot/sdk/generated/CommandExecuteEvent.java new file mode 100644 index 000000000..a9b0608db --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/CommandExecuteEvent.java @@ -0,0 +1,48 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code command.execute} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class CommandExecuteEvent extends SessionEvent { + + @Override + public String getType() { return "command.execute"; } + + @JsonProperty("data") + private CommandExecuteEventData data; + + public CommandExecuteEventData getData() { return data; } + public void setData(CommandExecuteEventData data) { this.data = data; } + + /** Data payload for {@link CommandExecuteEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record CommandExecuteEventData( + /** Unique identifier; used to respond via session.commands.handlePendingCommand() */ + @JsonProperty("requestId") String requestId, + /** The full command text (e.g., /deploy production) */ + @JsonProperty("command") String command, + /** Command name without leading / */ + @JsonProperty("commandName") String commandName, + /** Raw argument string after the command name */ + @JsonProperty("args") String args + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/CommandQueuedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/CommandQueuedEvent.java new file mode 100644 index 000000000..6599f4da6 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/CommandQueuedEvent.java @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code command.queued} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class CommandQueuedEvent extends SessionEvent { + + @Override + public String getType() { return "command.queued"; } + + @JsonProperty("data") + private CommandQueuedEventData data; + + public CommandQueuedEventData getData() { return data; } + public void setData(CommandQueuedEventData data) { this.data = data; } + + /** Data payload for {@link CommandQueuedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record CommandQueuedEventData( + /** Unique identifier for this request; used to respond via session.respondToQueuedCommand() */ + @JsonProperty("requestId") String requestId, + /** The slash command text to be executed (e.g., /help, /clear) */ + @JsonProperty("command") String command + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/CommandsChangedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/CommandsChangedEvent.java new file mode 100644 index 000000000..a7704b6c8 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/CommandsChangedEvent.java @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The {@code commands.changed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class CommandsChangedEvent extends SessionEvent { + + @Override + public String getType() { return "commands.changed"; } + + @JsonProperty("data") + private CommandsChangedEventData data; + + public CommandsChangedEventData getData() { return data; } + public void setData(CommandsChangedEventData data) { this.data = data; } + + /** Data payload for {@link CommandsChangedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record CommandsChangedEventData( + /** Current list of registered SDK commands */ + @JsonProperty("commands") List commands + ) { + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record CommandsChangedEventDataCommandsItem( + @JsonProperty("name") String name, + @JsonProperty("description") String description + ) { + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/ElicitationCompletedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/ElicitationCompletedEvent.java new file mode 100644 index 000000000..45cbf54c7 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/ElicitationCompletedEvent.java @@ -0,0 +1,69 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The {@code elicitation.completed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ElicitationCompletedEvent extends SessionEvent { + + @Override + public String getType() { return "elicitation.completed"; } + + @JsonProperty("data") + private ElicitationCompletedEventData data; + + public ElicitationCompletedEventData getData() { return data; } + public void setData(ElicitationCompletedEventData data) { this.data = data; } + + /** Data payload for {@link ElicitationCompletedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ElicitationCompletedEventData( + /** Request ID of the resolved elicitation request; clients should dismiss any UI for this request */ + @JsonProperty("requestId") String requestId, + /** The user action: "accept" (submitted form), "decline" (explicitly refused), or "cancel" (dismissed) */ + @JsonProperty("action") ElicitationCompletedEventDataAction action, + /** The submitted form data when action is 'accept'; keys match the requested schema fields */ + @JsonProperty("content") Map content + ) { + + /** The user action: "accept" (submitted form), "decline" (explicitly refused), or "cancel" (dismissed) */ + public enum ElicitationCompletedEventDataAction { + /** The {@code accept} variant. */ + ACCEPT("accept"), + /** The {@code decline} variant. */ + DECLINE("decline"), + /** The {@code cancel} variant. */ + CANCEL("cancel"); + + private final String value; + ElicitationCompletedEventDataAction(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ElicitationCompletedEventDataAction fromValue(String value) { + for (ElicitationCompletedEventDataAction v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ElicitationCompletedEventDataAction value: " + value); + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/ElicitationRequestedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/ElicitationRequestedEvent.java new file mode 100644 index 000000000..838afbc50 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/ElicitationRequestedEvent.java @@ -0,0 +1,89 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The {@code elicitation.requested} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ElicitationRequestedEvent extends SessionEvent { + + @Override + public String getType() { return "elicitation.requested"; } + + @JsonProperty("data") + private ElicitationRequestedEventData data; + + public ElicitationRequestedEventData getData() { return data; } + public void setData(ElicitationRequestedEventData data) { this.data = data; } + + /** Data payload for {@link ElicitationRequestedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ElicitationRequestedEventData( + /** Unique identifier for this elicitation request; used to respond via session.respondToElicitation() */ + @JsonProperty("requestId") String requestId, + /** Tool call ID from the LLM completion; used to correlate with CompletionChunk.toolCall.id for remote UIs */ + @JsonProperty("toolCallId") String toolCallId, + /** The source that initiated the request (MCP server name, or absent for agent-initiated) */ + @JsonProperty("elicitationSource") String elicitationSource, + /** Message describing what information is needed from the user */ + @JsonProperty("message") String message, + /** Elicitation mode; "form" for structured input, "url" for browser-based. Defaults to "form" when absent. */ + @JsonProperty("mode") ElicitationRequestedEventDataMode mode, + /** JSON Schema describing the form fields to present to the user (form mode only) */ + @JsonProperty("requestedSchema") ElicitationRequestedEventDataRequestedSchema requestedSchema, + /** URL to open in the user's browser (url mode only) */ + @JsonProperty("url") String url + ) { + + /** Elicitation mode; "form" for structured input, "url" for browser-based. Defaults to "form" when absent. */ + public enum ElicitationRequestedEventDataMode { + /** The {@code form} variant. */ + FORM("form"), + /** The {@code url} variant. */ + URL("url"); + + private final String value; + ElicitationRequestedEventDataMode(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ElicitationRequestedEventDataMode fromValue(String value) { + for (ElicitationRequestedEventDataMode v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ElicitationRequestedEventDataMode value: " + value); + } + } + + /** JSON Schema describing the form fields to present to the user (form mode only) */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ElicitationRequestedEventDataRequestedSchema( + /** Schema type indicator (always 'object') */ + @JsonProperty("type") String type, + /** Form field definitions, keyed by field name */ + @JsonProperty("properties") Map properties, + /** List of required field names */ + @JsonProperty("required") List required + ) { + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/ExitPlanModeCompletedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/ExitPlanModeCompletedEvent.java new file mode 100644 index 000000000..56c2c6681 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/ExitPlanModeCompletedEvent.java @@ -0,0 +1,50 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code exit_plan_mode.completed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ExitPlanModeCompletedEvent extends SessionEvent { + + @Override + public String getType() { return "exit_plan_mode.completed"; } + + @JsonProperty("data") + private ExitPlanModeCompletedEventData data; + + public ExitPlanModeCompletedEventData getData() { return data; } + public void setData(ExitPlanModeCompletedEventData data) { this.data = data; } + + /** Data payload for {@link ExitPlanModeCompletedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ExitPlanModeCompletedEventData( + /** Request ID of the resolved exit plan mode request; clients should dismiss any UI for this request */ + @JsonProperty("requestId") String requestId, + /** Whether the plan was approved by the user */ + @JsonProperty("approved") Boolean approved, + /** Which action the user selected (e.g. 'autopilot', 'interactive', 'exit_only') */ + @JsonProperty("selectedAction") String selectedAction, + /** Whether edits should be auto-approved without confirmation */ + @JsonProperty("autoApproveEdits") Boolean autoApproveEdits, + /** Free-form feedback from the user if they requested changes to the plan */ + @JsonProperty("feedback") String feedback + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/ExitPlanModeRequestedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/ExitPlanModeRequestedEvent.java new file mode 100644 index 000000000..de2bf45a8 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/ExitPlanModeRequestedEvent.java @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The {@code exit_plan_mode.requested} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ExitPlanModeRequestedEvent extends SessionEvent { + + @Override + public String getType() { return "exit_plan_mode.requested"; } + + @JsonProperty("data") + private ExitPlanModeRequestedEventData data; + + public ExitPlanModeRequestedEventData getData() { return data; } + public void setData(ExitPlanModeRequestedEventData data) { this.data = data; } + + /** Data payload for {@link ExitPlanModeRequestedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ExitPlanModeRequestedEventData( + /** Unique identifier for this request; used to respond via session.respondToExitPlanMode() */ + @JsonProperty("requestId") String requestId, + /** Summary of the plan that was created */ + @JsonProperty("summary") String summary, + /** Full content of the plan file */ + @JsonProperty("planContent") String planContent, + /** Available actions the user can take (e.g., approve, edit, reject) */ + @JsonProperty("actions") List actions, + /** The recommended action for the user to take */ + @JsonProperty("recommendedAction") String recommendedAction + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/ExternalToolCompletedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/ExternalToolCompletedEvent.java new file mode 100644 index 000000000..e9526c6fa --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/ExternalToolCompletedEvent.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code external_tool.completed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ExternalToolCompletedEvent extends SessionEvent { + + @Override + public String getType() { return "external_tool.completed"; } + + @JsonProperty("data") + private ExternalToolCompletedEventData data; + + public ExternalToolCompletedEventData getData() { return data; } + public void setData(ExternalToolCompletedEventData data) { this.data = data; } + + /** Data payload for {@link ExternalToolCompletedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ExternalToolCompletedEventData( + /** Request ID of the resolved external tool request; clients should dismiss any UI for this request */ + @JsonProperty("requestId") String requestId + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/ExternalToolRequestedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/ExternalToolRequestedEvent.java new file mode 100644 index 000000000..8e646c1a5 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/ExternalToolRequestedEvent.java @@ -0,0 +1,54 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code external_tool.requested} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ExternalToolRequestedEvent extends SessionEvent { + + @Override + public String getType() { return "external_tool.requested"; } + + @JsonProperty("data") + private ExternalToolRequestedEventData data; + + public ExternalToolRequestedEventData getData() { return data; } + public void setData(ExternalToolRequestedEventData data) { this.data = data; } + + /** Data payload for {@link ExternalToolRequestedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ExternalToolRequestedEventData( + /** Unique identifier for this request; used to respond via session.respondToExternalTool() */ + @JsonProperty("requestId") String requestId, + /** Session ID that this external tool request belongs to */ + @JsonProperty("sessionId") String sessionId, + /** Tool call ID assigned to this external tool invocation */ + @JsonProperty("toolCallId") String toolCallId, + /** Name of the external tool to invoke */ + @JsonProperty("toolName") String toolName, + /** Arguments to pass to the external tool */ + @JsonProperty("arguments") Object arguments, + /** W3C Trace Context traceparent header for the execute_tool span */ + @JsonProperty("traceparent") String traceparent, + /** W3C Trace Context tracestate header for the execute_tool span */ + @JsonProperty("tracestate") String tracestate + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/HookEndEvent.java b/src/generated/java/com/github/copilot/sdk/generated/HookEndEvent.java new file mode 100644 index 000000000..51de160c1 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/HookEndEvent.java @@ -0,0 +1,61 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code hook.end} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class HookEndEvent extends SessionEvent { + + @Override + public String getType() { return "hook.end"; } + + @JsonProperty("data") + private HookEndEventData data; + + public HookEndEventData getData() { return data; } + public void setData(HookEndEventData data) { this.data = data; } + + /** Data payload for {@link HookEndEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record HookEndEventData( + /** Identifier matching the corresponding hook.start event */ + @JsonProperty("hookInvocationId") String hookInvocationId, + /** Type of hook that was invoked (e.g., "preToolUse", "postToolUse", "sessionStart") */ + @JsonProperty("hookType") String hookType, + /** Output data produced by the hook */ + @JsonProperty("output") Object output, + /** Whether the hook completed successfully */ + @JsonProperty("success") Boolean success, + /** Error details when the hook failed */ + @JsonProperty("error") HookEndEventDataError error + ) { + + /** Error details when the hook failed */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record HookEndEventDataError( + /** Human-readable error message */ + @JsonProperty("message") String message, + /** Error stack trace, when available */ + @JsonProperty("stack") String stack + ) { + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/HookStartEvent.java b/src/generated/java/com/github/copilot/sdk/generated/HookStartEvent.java new file mode 100644 index 000000000..ffca1dfe0 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/HookStartEvent.java @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code hook.start} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class HookStartEvent extends SessionEvent { + + @Override + public String getType() { return "hook.start"; } + + @JsonProperty("data") + private HookStartEventData data; + + public HookStartEventData getData() { return data; } + public void setData(HookStartEventData data) { this.data = data; } + + /** Data payload for {@link HookStartEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record HookStartEventData( + /** Unique identifier for this hook invocation */ + @JsonProperty("hookInvocationId") String hookInvocationId, + /** Type of hook being invoked (e.g., "preToolUse", "postToolUse", "sessionStart") */ + @JsonProperty("hookType") String hookType, + /** Input data passed to the hook */ + @JsonProperty("input") Object input + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/McpOauthCompletedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/McpOauthCompletedEvent.java new file mode 100644 index 000000000..3d410bf2d --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/McpOauthCompletedEvent.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code mcp.oauth_completed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class McpOauthCompletedEvent extends SessionEvent { + + @Override + public String getType() { return "mcp.oauth_completed"; } + + @JsonProperty("data") + private McpOauthCompletedEventData data; + + public McpOauthCompletedEventData getData() { return data; } + public void setData(McpOauthCompletedEventData data) { this.data = data; } + + /** Data payload for {@link McpOauthCompletedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record McpOauthCompletedEventData( + /** Request ID of the resolved OAuth request */ + @JsonProperty("requestId") String requestId + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/McpOauthRequiredEvent.java b/src/generated/java/com/github/copilot/sdk/generated/McpOauthRequiredEvent.java new file mode 100644 index 000000000..748cdfc9b --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/McpOauthRequiredEvent.java @@ -0,0 +1,59 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code mcp.oauth_required} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class McpOauthRequiredEvent extends SessionEvent { + + @Override + public String getType() { return "mcp.oauth_required"; } + + @JsonProperty("data") + private McpOauthRequiredEventData data; + + public McpOauthRequiredEventData getData() { return data; } + public void setData(McpOauthRequiredEventData data) { this.data = data; } + + /** Data payload for {@link McpOauthRequiredEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record McpOauthRequiredEventData( + /** Unique identifier for this OAuth request; used to respond via session.respondToMcpOAuth() */ + @JsonProperty("requestId") String requestId, + /** Display name of the MCP server that requires OAuth */ + @JsonProperty("serverName") String serverName, + /** URL of the MCP server that requires OAuth */ + @JsonProperty("serverUrl") String serverUrl, + /** Static OAuth client configuration, if the server specifies one */ + @JsonProperty("staticClientConfig") McpOauthRequiredEventDataStaticClientConfig staticClientConfig + ) { + + /** Static OAuth client configuration, if the server specifies one */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record McpOauthRequiredEventDataStaticClientConfig( + /** OAuth client ID for the server */ + @JsonProperty("clientId") String clientId, + /** Whether this is a public OAuth client */ + @JsonProperty("publicClient") Boolean publicClient + ) { + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/PendingMessagesModifiedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/PendingMessagesModifiedEvent.java new file mode 100644 index 000000000..56f8ed520 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/PendingMessagesModifiedEvent.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code pending_messages.modified} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class PendingMessagesModifiedEvent extends SessionEvent { + + @Override + public String getType() { return "pending_messages.modified"; } + + @JsonProperty("data") + private PendingMessagesModifiedEventData data; + + public PendingMessagesModifiedEventData getData() { return data; } + public void setData(PendingMessagesModifiedEventData data) { this.data = data; } + + /** Data payload for {@link PendingMessagesModifiedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record PendingMessagesModifiedEventData() { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/PermissionCompletedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/PermissionCompletedEvent.java new file mode 100644 index 000000000..06300a5ae --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/PermissionCompletedEvent.java @@ -0,0 +1,81 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code permission.completed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class PermissionCompletedEvent extends SessionEvent { + + @Override + public String getType() { return "permission.completed"; } + + @JsonProperty("data") + private PermissionCompletedEventData data; + + public PermissionCompletedEventData getData() { return data; } + public void setData(PermissionCompletedEventData data) { this.data = data; } + + /** Data payload for {@link PermissionCompletedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record PermissionCompletedEventData( + /** Request ID of the resolved permission request; clients should dismiss any UI for this request */ + @JsonProperty("requestId") String requestId, + /** The result of the permission request */ + @JsonProperty("result") PermissionCompletedEventDataResult result + ) { + + /** The result of the permission request */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record PermissionCompletedEventDataResult( + /** The outcome of the permission request */ + @JsonProperty("kind") PermissionCompletedEventDataResultKind kind + ) { + + /** The outcome of the permission request */ + public enum PermissionCompletedEventDataResultKind { + /** The {@code approved} variant. */ + APPROVED("approved"), + /** The {@code denied-by-rules} variant. */ + DENIED_BY_RULES("denied-by-rules"), + /** The {@code denied-no-approval-rule-and-could-not-request-from-user} variant. */ + DENIED_NO_APPROVAL_RULE_AND_COULD_NOT_REQUEST_FROM_USER("denied-no-approval-rule-and-could-not-request-from-user"), + /** The {@code denied-interactively-by-user} variant. */ + DENIED_INTERACTIVELY_BY_USER("denied-interactively-by-user"), + /** The {@code denied-by-content-exclusion-policy} variant. */ + DENIED_BY_CONTENT_EXCLUSION_POLICY("denied-by-content-exclusion-policy"), + /** The {@code denied-by-permission-request-hook} variant. */ + DENIED_BY_PERMISSION_REQUEST_HOOK("denied-by-permission-request-hook"); + + private final String value; + PermissionCompletedEventDataResultKind(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static PermissionCompletedEventDataResultKind fromValue(String value) { + for (PermissionCompletedEventDataResultKind v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown PermissionCompletedEventDataResultKind value: " + value); + } + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/PermissionRequestedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/PermissionRequestedEvent.java new file mode 100644 index 000000000..83a1967c7 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/PermissionRequestedEvent.java @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code permission.requested} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class PermissionRequestedEvent extends SessionEvent { + + @Override + public String getType() { return "permission.requested"; } + + @JsonProperty("data") + private PermissionRequestedEventData data; + + public PermissionRequestedEventData getData() { return data; } + public void setData(PermissionRequestedEventData data) { this.data = data; } + + /** Data payload for {@link PermissionRequestedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record PermissionRequestedEventData( + /** Unique identifier for this permission request; used to respond via session.respondToPermission() */ + @JsonProperty("requestId") String requestId, + /** Details of the permission being requested */ + @JsonProperty("permissionRequest") Object permissionRequest, + /** When true, this permission was already resolved by a permissionRequest hook and requires no client action */ + @JsonProperty("resolvedByHook") Boolean resolvedByHook + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SamplingCompletedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SamplingCompletedEvent.java new file mode 100644 index 000000000..ae2157509 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SamplingCompletedEvent.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code sampling.completed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SamplingCompletedEvent extends SessionEvent { + + @Override + public String getType() { return "sampling.completed"; } + + @JsonProperty("data") + private SamplingCompletedEventData data; + + public SamplingCompletedEventData getData() { return data; } + public void setData(SamplingCompletedEventData data) { this.data = data; } + + /** Data payload for {@link SamplingCompletedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SamplingCompletedEventData( + /** Request ID of the resolved sampling request; clients should dismiss any UI for this request */ + @JsonProperty("requestId") String requestId + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SamplingRequestedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SamplingRequestedEvent.java new file mode 100644 index 000000000..7b92f5faf --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SamplingRequestedEvent.java @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code sampling.requested} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SamplingRequestedEvent extends SessionEvent { + + @Override + public String getType() { return "sampling.requested"; } + + @JsonProperty("data") + private SamplingRequestedEventData data; + + public SamplingRequestedEventData getData() { return data; } + public void setData(SamplingRequestedEventData data) { this.data = data; } + + /** Data payload for {@link SamplingRequestedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SamplingRequestedEventData( + /** Unique identifier for this sampling request; used to respond via session.respondToSampling() */ + @JsonProperty("requestId") String requestId, + /** Name of the MCP server that initiated the sampling request */ + @JsonProperty("serverName") String serverName, + /** The JSON-RPC request ID from the MCP protocol */ + @JsonProperty("mcpRequestId") Object mcpRequestId + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionBackgroundTasksChangedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionBackgroundTasksChangedEvent.java new file mode 100644 index 000000000..fa996cf0e --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionBackgroundTasksChangedEvent.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.background_tasks_changed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionBackgroundTasksChangedEvent extends SessionEvent { + + @Override + public String getType() { return "session.background_tasks_changed"; } + + @JsonProperty("data") + private SessionBackgroundTasksChangedEventData data; + + public SessionBackgroundTasksChangedEventData getData() { return data; } + public void setData(SessionBackgroundTasksChangedEventData data) { this.data = data; } + + /** Data payload for {@link SessionBackgroundTasksChangedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionBackgroundTasksChangedEventData() { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionCompactionCompleteEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionCompactionCompleteEvent.java new file mode 100644 index 000000000..14728cf20 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionCompactionCompleteEvent.java @@ -0,0 +1,83 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.compaction_complete} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionCompactionCompleteEvent extends SessionEvent { + + @Override + public String getType() { return "session.compaction_complete"; } + + @JsonProperty("data") + private SessionCompactionCompleteEventData data; + + public SessionCompactionCompleteEventData getData() { return data; } + public void setData(SessionCompactionCompleteEventData data) { this.data = data; } + + /** Data payload for {@link SessionCompactionCompleteEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionCompactionCompleteEventData( + /** Whether compaction completed successfully */ + @JsonProperty("success") Boolean success, + /** Error message if compaction failed */ + @JsonProperty("error") String error, + /** Total tokens in conversation before compaction */ + @JsonProperty("preCompactionTokens") Double preCompactionTokens, + /** Total tokens in conversation after compaction */ + @JsonProperty("postCompactionTokens") Double postCompactionTokens, + /** Number of messages before compaction */ + @JsonProperty("preCompactionMessagesLength") Double preCompactionMessagesLength, + /** Number of messages removed during compaction */ + @JsonProperty("messagesRemoved") Double messagesRemoved, + /** Number of tokens removed during compaction */ + @JsonProperty("tokensRemoved") Double tokensRemoved, + /** LLM-generated summary of the compacted conversation history */ + @JsonProperty("summaryContent") String summaryContent, + /** Checkpoint snapshot number created for recovery */ + @JsonProperty("checkpointNumber") Double checkpointNumber, + /** File path where the checkpoint was stored */ + @JsonProperty("checkpointPath") String checkpointPath, + /** Token usage breakdown for the compaction LLM call */ + @JsonProperty("compactionTokensUsed") SessionCompactionCompleteEventDataCompactionTokensUsed compactionTokensUsed, + /** GitHub request tracing ID (x-github-request-id header) for the compaction LLM call */ + @JsonProperty("requestId") String requestId, + /** Token count from system message(s) after compaction */ + @JsonProperty("systemTokens") Double systemTokens, + /** Token count from non-system messages (user, assistant, tool) after compaction */ + @JsonProperty("conversationTokens") Double conversationTokens, + /** Token count from tool definitions after compaction */ + @JsonProperty("toolDefinitionsTokens") Double toolDefinitionsTokens + ) { + + /** Token usage breakdown for the compaction LLM call */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionCompactionCompleteEventDataCompactionTokensUsed( + /** Input tokens consumed by the compaction LLM call */ + @JsonProperty("input") Double input, + /** Output tokens produced by the compaction LLM call */ + @JsonProperty("output") Double output, + /** Cached input tokens reused in the compaction LLM call */ + @JsonProperty("cachedInput") Double cachedInput + ) { + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionCompactionStartEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionCompactionStartEvent.java new file mode 100644 index 000000000..2e0fb6d6f --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionCompactionStartEvent.java @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.compaction_start} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionCompactionStartEvent extends SessionEvent { + + @Override + public String getType() { return "session.compaction_start"; } + + @JsonProperty("data") + private SessionCompactionStartEventData data; + + public SessionCompactionStartEventData getData() { return data; } + public void setData(SessionCompactionStartEventData data) { this.data = data; } + + /** Data payload for {@link SessionCompactionStartEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionCompactionStartEventData( + /** Token count from system message(s) at compaction start */ + @JsonProperty("systemTokens") Double systemTokens, + /** Token count from non-system messages (user, assistant, tool) at compaction start */ + @JsonProperty("conversationTokens") Double conversationTokens, + /** Token count from tool definitions at compaction start */ + @JsonProperty("toolDefinitionsTokens") Double toolDefinitionsTokens + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionContextChangedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionContextChangedEvent.java new file mode 100644 index 000000000..5399860a2 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionContextChangedEvent.java @@ -0,0 +1,74 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.context_changed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionContextChangedEvent extends SessionEvent { + + @Override + public String getType() { return "session.context_changed"; } + + @JsonProperty("data") + private SessionContextChangedEventData data; + + public SessionContextChangedEventData getData() { return data; } + public void setData(SessionContextChangedEventData data) { this.data = data; } + + /** Data payload for {@link SessionContextChangedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionContextChangedEventData( + /** Current working directory path */ + @JsonProperty("cwd") String cwd, + /** Root directory of the git repository, resolved via git rev-parse */ + @JsonProperty("gitRoot") String gitRoot, + /** Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps) */ + @JsonProperty("repository") String repository, + /** Hosting platform type of the repository (github or ado) */ + @JsonProperty("hostType") SessionContextChangedEventDataHostType hostType, + /** Current git branch name */ + @JsonProperty("branch") String branch, + /** Head commit of current git branch at session start time */ + @JsonProperty("headCommit") String headCommit, + /** Base commit of current git branch at session start time */ + @JsonProperty("baseCommit") String baseCommit + ) { + + /** Hosting platform type of the repository (github or ado) */ + public enum SessionContextChangedEventDataHostType { + /** The {@code github} variant. */ + GITHUB("github"), + /** The {@code ado} variant. */ + ADO("ado"); + + private final String value; + SessionContextChangedEventDataHostType(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionContextChangedEventDataHostType fromValue(String value) { + for (SessionContextChangedEventDataHostType v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionContextChangedEventDataHostType value: " + value); + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionCustomAgentsUpdatedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionCustomAgentsUpdatedEvent.java new file mode 100644 index 000000000..0a0c3f761 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionCustomAgentsUpdatedEvent.java @@ -0,0 +1,69 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The {@code session.custom_agents_updated} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionCustomAgentsUpdatedEvent extends SessionEvent { + + @Override + public String getType() { return "session.custom_agents_updated"; } + + @JsonProperty("data") + private SessionCustomAgentsUpdatedEventData data; + + public SessionCustomAgentsUpdatedEventData getData() { return data; } + public void setData(SessionCustomAgentsUpdatedEventData data) { this.data = data; } + + /** Data payload for {@link SessionCustomAgentsUpdatedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionCustomAgentsUpdatedEventData( + /** Array of loaded custom agent metadata */ + @JsonProperty("agents") List agents, + /** Non-fatal warnings from agent loading */ + @JsonProperty("warnings") List warnings, + /** Fatal errors from agent loading */ + @JsonProperty("errors") List errors + ) { + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionCustomAgentsUpdatedEventDataAgentsItem( + /** Unique identifier for the agent */ + @JsonProperty("id") String id, + /** Internal name of the agent */ + @JsonProperty("name") String name, + /** Human-readable display name */ + @JsonProperty("displayName") String displayName, + /** Description of what the agent does */ + @JsonProperty("description") String description, + /** Source location: user, project, inherited, remote, or plugin */ + @JsonProperty("source") String source, + /** List of tool names available to this agent */ + @JsonProperty("tools") List tools, + /** Whether the agent can be selected by the user */ + @JsonProperty("userInvocable") Boolean userInvocable, + /** Model override for this agent, if set */ + @JsonProperty("model") String model + ) { + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionErrorEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionErrorEvent.java new file mode 100644 index 000000000..33dc68834 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionErrorEvent.java @@ -0,0 +1,52 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.error} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionErrorEvent extends SessionEvent { + + @Override + public String getType() { return "session.error"; } + + @JsonProperty("data") + private SessionErrorEventData data; + + public SessionErrorEventData getData() { return data; } + public void setData(SessionErrorEventData data) { this.data = data; } + + /** Data payload for {@link SessionErrorEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionErrorEventData( + /** Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", "context_limit", "query") */ + @JsonProperty("errorType") String errorType, + /** Human-readable error message */ + @JsonProperty("message") String message, + /** Error stack trace, when available */ + @JsonProperty("stack") String stack, + /** HTTP status code from the upstream request, if applicable */ + @JsonProperty("statusCode") Long statusCode, + /** GitHub request tracing ID (x-github-request-id header) for correlating with server-side logs */ + @JsonProperty("providerCallId") String providerCallId, + /** Optional URL associated with this error that the user can open in a browser */ + @JsonProperty("url") String url + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionEvent.java new file mode 100644 index 000000000..1b63b238e --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionEvent.java @@ -0,0 +1,215 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import java.time.OffsetDateTime; +import java.util.UUID; +import javax.annotation.processing.Generated; + +/** + * Base class for all generated session events. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true, defaultImpl = UnknownSessionEvent.class) +@JsonSubTypes({ + @JsonSubTypes.Type(value = SessionStartEvent.class, name = "session.start"), + @JsonSubTypes.Type(value = SessionResumeEvent.class, name = "session.resume"), + @JsonSubTypes.Type(value = SessionRemoteSteerableChangedEvent.class, name = "session.remote_steerable_changed"), + @JsonSubTypes.Type(value = SessionErrorEvent.class, name = "session.error"), + @JsonSubTypes.Type(value = SessionIdleEvent.class, name = "session.idle"), + @JsonSubTypes.Type(value = SessionTitleChangedEvent.class, name = "session.title_changed"), + @JsonSubTypes.Type(value = SessionInfoEvent.class, name = "session.info"), + @JsonSubTypes.Type(value = SessionWarningEvent.class, name = "session.warning"), + @JsonSubTypes.Type(value = SessionModelChangeEvent.class, name = "session.model_change"), + @JsonSubTypes.Type(value = SessionModeChangedEvent.class, name = "session.mode_changed"), + @JsonSubTypes.Type(value = SessionPlanChangedEvent.class, name = "session.plan_changed"), + @JsonSubTypes.Type(value = SessionWorkspaceFileChangedEvent.class, name = "session.workspace_file_changed"), + @JsonSubTypes.Type(value = SessionHandoffEvent.class, name = "session.handoff"), + @JsonSubTypes.Type(value = SessionTruncationEvent.class, name = "session.truncation"), + @JsonSubTypes.Type(value = SessionSnapshotRewindEvent.class, name = "session.snapshot_rewind"), + @JsonSubTypes.Type(value = SessionShutdownEvent.class, name = "session.shutdown"), + @JsonSubTypes.Type(value = SessionContextChangedEvent.class, name = "session.context_changed"), + @JsonSubTypes.Type(value = SessionUsageInfoEvent.class, name = "session.usage_info"), + @JsonSubTypes.Type(value = SessionCompactionStartEvent.class, name = "session.compaction_start"), + @JsonSubTypes.Type(value = SessionCompactionCompleteEvent.class, name = "session.compaction_complete"), + @JsonSubTypes.Type(value = SessionTaskCompleteEvent.class, name = "session.task_complete"), + @JsonSubTypes.Type(value = UserMessageEvent.class, name = "user.message"), + @JsonSubTypes.Type(value = PendingMessagesModifiedEvent.class, name = "pending_messages.modified"), + @JsonSubTypes.Type(value = AssistantTurnStartEvent.class, name = "assistant.turn_start"), + @JsonSubTypes.Type(value = AssistantIntentEvent.class, name = "assistant.intent"), + @JsonSubTypes.Type(value = AssistantReasoningEvent.class, name = "assistant.reasoning"), + @JsonSubTypes.Type(value = AssistantReasoningDeltaEvent.class, name = "assistant.reasoning_delta"), + @JsonSubTypes.Type(value = AssistantStreamingDeltaEvent.class, name = "assistant.streaming_delta"), + @JsonSubTypes.Type(value = AssistantMessageEvent.class, name = "assistant.message"), + @JsonSubTypes.Type(value = AssistantMessageDeltaEvent.class, name = "assistant.message_delta"), + @JsonSubTypes.Type(value = AssistantTurnEndEvent.class, name = "assistant.turn_end"), + @JsonSubTypes.Type(value = AssistantUsageEvent.class, name = "assistant.usage"), + @JsonSubTypes.Type(value = AbortEvent.class, name = "abort"), + @JsonSubTypes.Type(value = ToolUserRequestedEvent.class, name = "tool.user_requested"), + @JsonSubTypes.Type(value = ToolExecutionStartEvent.class, name = "tool.execution_start"), + @JsonSubTypes.Type(value = ToolExecutionPartialResultEvent.class, name = "tool.execution_partial_result"), + @JsonSubTypes.Type(value = ToolExecutionProgressEvent.class, name = "tool.execution_progress"), + @JsonSubTypes.Type(value = ToolExecutionCompleteEvent.class, name = "tool.execution_complete"), + @JsonSubTypes.Type(value = SkillInvokedEvent.class, name = "skill.invoked"), + @JsonSubTypes.Type(value = SubagentStartedEvent.class, name = "subagent.started"), + @JsonSubTypes.Type(value = SubagentCompletedEvent.class, name = "subagent.completed"), + @JsonSubTypes.Type(value = SubagentFailedEvent.class, name = "subagent.failed"), + @JsonSubTypes.Type(value = SubagentSelectedEvent.class, name = "subagent.selected"), + @JsonSubTypes.Type(value = SubagentDeselectedEvent.class, name = "subagent.deselected"), + @JsonSubTypes.Type(value = HookStartEvent.class, name = "hook.start"), + @JsonSubTypes.Type(value = HookEndEvent.class, name = "hook.end"), + @JsonSubTypes.Type(value = SystemMessageEvent.class, name = "system.message"), + @JsonSubTypes.Type(value = SystemNotificationEvent.class, name = "system.notification"), + @JsonSubTypes.Type(value = PermissionRequestedEvent.class, name = "permission.requested"), + @JsonSubTypes.Type(value = PermissionCompletedEvent.class, name = "permission.completed"), + @JsonSubTypes.Type(value = UserInputRequestedEvent.class, name = "user_input.requested"), + @JsonSubTypes.Type(value = UserInputCompletedEvent.class, name = "user_input.completed"), + @JsonSubTypes.Type(value = ElicitationRequestedEvent.class, name = "elicitation.requested"), + @JsonSubTypes.Type(value = ElicitationCompletedEvent.class, name = "elicitation.completed"), + @JsonSubTypes.Type(value = SamplingRequestedEvent.class, name = "sampling.requested"), + @JsonSubTypes.Type(value = SamplingCompletedEvent.class, name = "sampling.completed"), + @JsonSubTypes.Type(value = McpOauthRequiredEvent.class, name = "mcp.oauth_required"), + @JsonSubTypes.Type(value = McpOauthCompletedEvent.class, name = "mcp.oauth_completed"), + @JsonSubTypes.Type(value = ExternalToolRequestedEvent.class, name = "external_tool.requested"), + @JsonSubTypes.Type(value = ExternalToolCompletedEvent.class, name = "external_tool.completed"), + @JsonSubTypes.Type(value = CommandQueuedEvent.class, name = "command.queued"), + @JsonSubTypes.Type(value = CommandExecuteEvent.class, name = "command.execute"), + @JsonSubTypes.Type(value = CommandCompletedEvent.class, name = "command.completed"), + @JsonSubTypes.Type(value = CommandsChangedEvent.class, name = "commands.changed"), + @JsonSubTypes.Type(value = CapabilitiesChangedEvent.class, name = "capabilities.changed"), + @JsonSubTypes.Type(value = ExitPlanModeRequestedEvent.class, name = "exit_plan_mode.requested"), + @JsonSubTypes.Type(value = ExitPlanModeCompletedEvent.class, name = "exit_plan_mode.completed"), + @JsonSubTypes.Type(value = SessionToolsUpdatedEvent.class, name = "session.tools_updated"), + @JsonSubTypes.Type(value = SessionBackgroundTasksChangedEvent.class, name = "session.background_tasks_changed"), + @JsonSubTypes.Type(value = SessionSkillsLoadedEvent.class, name = "session.skills_loaded"), + @JsonSubTypes.Type(value = SessionCustomAgentsUpdatedEvent.class, name = "session.custom_agents_updated"), + @JsonSubTypes.Type(value = SessionMcpServersLoadedEvent.class, name = "session.mcp_servers_loaded"), + @JsonSubTypes.Type(value = SessionMcpServerStatusChangedEvent.class, name = "session.mcp_server_status_changed"), + @JsonSubTypes.Type(value = SessionExtensionsLoadedEvent.class, name = "session.extensions_loaded") +}) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public abstract sealed class SessionEvent permits + SessionStartEvent, + SessionResumeEvent, + SessionRemoteSteerableChangedEvent, + SessionErrorEvent, + SessionIdleEvent, + SessionTitleChangedEvent, + SessionInfoEvent, + SessionWarningEvent, + SessionModelChangeEvent, + SessionModeChangedEvent, + SessionPlanChangedEvent, + SessionWorkspaceFileChangedEvent, + SessionHandoffEvent, + SessionTruncationEvent, + SessionSnapshotRewindEvent, + SessionShutdownEvent, + SessionContextChangedEvent, + SessionUsageInfoEvent, + SessionCompactionStartEvent, + SessionCompactionCompleteEvent, + SessionTaskCompleteEvent, + UserMessageEvent, + PendingMessagesModifiedEvent, + AssistantTurnStartEvent, + AssistantIntentEvent, + AssistantReasoningEvent, + AssistantReasoningDeltaEvent, + AssistantStreamingDeltaEvent, + AssistantMessageEvent, + AssistantMessageDeltaEvent, + AssistantTurnEndEvent, + AssistantUsageEvent, + AbortEvent, + ToolUserRequestedEvent, + ToolExecutionStartEvent, + ToolExecutionPartialResultEvent, + ToolExecutionProgressEvent, + ToolExecutionCompleteEvent, + SkillInvokedEvent, + SubagentStartedEvent, + SubagentCompletedEvent, + SubagentFailedEvent, + SubagentSelectedEvent, + SubagentDeselectedEvent, + HookStartEvent, + HookEndEvent, + SystemMessageEvent, + SystemNotificationEvent, + PermissionRequestedEvent, + PermissionCompletedEvent, + UserInputRequestedEvent, + UserInputCompletedEvent, + ElicitationRequestedEvent, + ElicitationCompletedEvent, + SamplingRequestedEvent, + SamplingCompletedEvent, + McpOauthRequiredEvent, + McpOauthCompletedEvent, + ExternalToolRequestedEvent, + ExternalToolCompletedEvent, + CommandQueuedEvent, + CommandExecuteEvent, + CommandCompletedEvent, + CommandsChangedEvent, + CapabilitiesChangedEvent, + ExitPlanModeRequestedEvent, + ExitPlanModeCompletedEvent, + SessionToolsUpdatedEvent, + SessionBackgroundTasksChangedEvent, + SessionSkillsLoadedEvent, + SessionCustomAgentsUpdatedEvent, + SessionMcpServersLoadedEvent, + SessionMcpServerStatusChangedEvent, + SessionExtensionsLoadedEvent, + UnknownSessionEvent { + + /** Unique event identifier (UUID v4), generated when the event is emitted. */ + @JsonProperty("id") + private UUID id; + + /** ISO 8601 timestamp when the event was created. */ + @JsonProperty("timestamp") + private OffsetDateTime timestamp; + + /** ID of the chronologically preceding event in the session. Null for the first event. */ + @JsonProperty("parentId") + private UUID parentId; + + /** When true, the event is transient and not persisted to the session event log on disk. */ + @JsonProperty("ephemeral") + private Boolean ephemeral; + + /** + * Returns the event-type discriminator string (e.g., {@code "session.idle"}). + * + * @return the event type + */ + public abstract String getType(); + + public UUID getId() { return id; } + public void setId(UUID id) { this.id = id; } + + public OffsetDateTime getTimestamp() { return timestamp; } + public void setTimestamp(OffsetDateTime timestamp) { this.timestamp = timestamp; } + + public UUID getParentId() { return parentId; } + public void setParentId(UUID parentId) { this.parentId = parentId; } + + public Boolean getEphemeral() { return ephemeral; } + public void setEphemeral(Boolean ephemeral) { this.ephemeral = ephemeral; } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionExtensionsLoadedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionExtensionsLoadedEvent.java new file mode 100644 index 000000000..969851a78 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionExtensionsLoadedEvent.java @@ -0,0 +1,101 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The {@code session.extensions_loaded} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionExtensionsLoadedEvent extends SessionEvent { + + @Override + public String getType() { return "session.extensions_loaded"; } + + @JsonProperty("data") + private SessionExtensionsLoadedEventData data; + + public SessionExtensionsLoadedEventData getData() { return data; } + public void setData(SessionExtensionsLoadedEventData data) { this.data = data; } + + /** Data payload for {@link SessionExtensionsLoadedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionExtensionsLoadedEventData( + /** Array of discovered extensions and their status */ + @JsonProperty("extensions") List extensions + ) { + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionExtensionsLoadedEventDataExtensionsItem( + /** Source-qualified extension ID (e.g., 'project:my-ext', 'user:auth-helper') */ + @JsonProperty("id") String id, + /** Extension name (directory name) */ + @JsonProperty("name") String name, + /** Discovery source */ + @JsonProperty("source") SessionExtensionsLoadedEventDataExtensionsItemSource source, + /** Current status: running, disabled, failed, or starting */ + @JsonProperty("status") SessionExtensionsLoadedEventDataExtensionsItemStatus status + ) { + + /** Discovery source */ + public enum SessionExtensionsLoadedEventDataExtensionsItemSource { + /** The {@code project} variant. */ + PROJECT("project"), + /** The {@code user} variant. */ + USER("user"); + + private final String value; + SessionExtensionsLoadedEventDataExtensionsItemSource(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionExtensionsLoadedEventDataExtensionsItemSource fromValue(String value) { + for (SessionExtensionsLoadedEventDataExtensionsItemSource v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionExtensionsLoadedEventDataExtensionsItemSource value: " + value); + } + } + + /** Current status: running, disabled, failed, or starting */ + public enum SessionExtensionsLoadedEventDataExtensionsItemStatus { + /** The {@code running} variant. */ + RUNNING("running"), + /** The {@code disabled} variant. */ + DISABLED("disabled"), + /** The {@code failed} variant. */ + FAILED("failed"), + /** The {@code starting} variant. */ + STARTING("starting"); + + private final String value; + SessionExtensionsLoadedEventDataExtensionsItemStatus(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionExtensionsLoadedEventDataExtensionsItemStatus fromValue(String value) { + for (SessionExtensionsLoadedEventDataExtensionsItemStatus v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionExtensionsLoadedEventDataExtensionsItemStatus value: " + value); + } + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionHandoffEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionHandoffEvent.java new file mode 100644 index 000000000..431108733 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionHandoffEvent.java @@ -0,0 +1,88 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.OffsetDateTime; +import javax.annotation.processing.Generated; + +/** + * The {@code session.handoff} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionHandoffEvent extends SessionEvent { + + @Override + public String getType() { return "session.handoff"; } + + @JsonProperty("data") + private SessionHandoffEventData data; + + public SessionHandoffEventData getData() { return data; } + public void setData(SessionHandoffEventData data) { this.data = data; } + + /** Data payload for {@link SessionHandoffEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionHandoffEventData( + /** ISO 8601 timestamp when the handoff occurred */ + @JsonProperty("handoffTime") OffsetDateTime handoffTime, + /** Origin type of the session being handed off */ + @JsonProperty("sourceType") SessionHandoffEventDataSourceType sourceType, + /** Repository context for the handed-off session */ + @JsonProperty("repository") SessionHandoffEventDataRepository repository, + /** Additional context information for the handoff */ + @JsonProperty("context") String context, + /** Summary of the work done in the source session */ + @JsonProperty("summary") String summary, + /** Session ID of the remote session being handed off */ + @JsonProperty("remoteSessionId") String remoteSessionId, + /** GitHub host URL for the source session (e.g., https://github.com or https://tenant.ghe.com) */ + @JsonProperty("host") String host + ) { + + /** Origin type of the session being handed off */ + public enum SessionHandoffEventDataSourceType { + /** The {@code remote} variant. */ + REMOTE("remote"), + /** The {@code local} variant. */ + LOCAL("local"); + + private final String value; + SessionHandoffEventDataSourceType(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionHandoffEventDataSourceType fromValue(String value) { + for (SessionHandoffEventDataSourceType v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionHandoffEventDataSourceType value: " + value); + } + } + + /** Repository context for the handed-off session */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionHandoffEventDataRepository( + /** Repository owner (user or organization) */ + @JsonProperty("owner") String owner, + /** Repository name */ + @JsonProperty("name") String name, + /** Git branch name, if applicable */ + @JsonProperty("branch") String branch + ) { + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionIdleEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionIdleEvent.java new file mode 100644 index 000000000..86376ae7c --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionIdleEvent.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.idle} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionIdleEvent extends SessionEvent { + + @Override + public String getType() { return "session.idle"; } + + @JsonProperty("data") + private SessionIdleEventData data; + + public SessionIdleEventData getData() { return data; } + public void setData(SessionIdleEventData data) { this.data = data; } + + /** Data payload for {@link SessionIdleEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionIdleEventData( + /** True when the preceding agentic loop was cancelled via abort signal */ + @JsonProperty("aborted") Boolean aborted + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionInfoEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionInfoEvent.java new file mode 100644 index 000000000..4dee36ba5 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionInfoEvent.java @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.info} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionInfoEvent extends SessionEvent { + + @Override + public String getType() { return "session.info"; } + + @JsonProperty("data") + private SessionInfoEventData data; + + public SessionInfoEventData getData() { return data; } + public void setData(SessionInfoEventData data) { this.data = data; } + + /** Data payload for {@link SessionInfoEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionInfoEventData( + /** Category of informational message (e.g., "notification", "timing", "context_window", "mcp", "snapshot", "configuration", "authentication", "model") */ + @JsonProperty("infoType") String infoType, + /** Human-readable informational message for display in the timeline */ + @JsonProperty("message") String message, + /** Optional URL associated with this message that the user can open in a browser */ + @JsonProperty("url") String url + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionMcpServerStatusChangedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionMcpServerStatusChangedEvent.java new file mode 100644 index 000000000..7bf09f7f5 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionMcpServerStatusChangedEvent.java @@ -0,0 +1,72 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.mcp_server_status_changed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionMcpServerStatusChangedEvent extends SessionEvent { + + @Override + public String getType() { return "session.mcp_server_status_changed"; } + + @JsonProperty("data") + private SessionMcpServerStatusChangedEventData data; + + public SessionMcpServerStatusChangedEventData getData() { return data; } + public void setData(SessionMcpServerStatusChangedEventData data) { this.data = data; } + + /** Data payload for {@link SessionMcpServerStatusChangedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionMcpServerStatusChangedEventData( + /** Name of the MCP server whose status changed */ + @JsonProperty("serverName") String serverName, + /** New connection status: connected, failed, needs-auth, pending, disabled, or not_configured */ + @JsonProperty("status") SessionMcpServerStatusChangedEventDataStatus status + ) { + + /** New connection status: connected, failed, needs-auth, pending, disabled, or not_configured */ + public enum SessionMcpServerStatusChangedEventDataStatus { + /** The {@code connected} variant. */ + CONNECTED("connected"), + /** The {@code failed} variant. */ + FAILED("failed"), + /** The {@code needs-auth} variant. */ + NEEDS_AUTH("needs-auth"), + /** The {@code pending} variant. */ + PENDING("pending"), + /** The {@code disabled} variant. */ + DISABLED("disabled"), + /** The {@code not_configured} variant. */ + NOT_CONFIGURED("not_configured"); + + private final String value; + SessionMcpServerStatusChangedEventDataStatus(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionMcpServerStatusChangedEventDataStatus fromValue(String value) { + for (SessionMcpServerStatusChangedEventDataStatus v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionMcpServerStatusChangedEventDataStatus value: " + value); + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionMcpServersLoadedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionMcpServersLoadedEvent.java new file mode 100644 index 000000000..e6ab5f25d --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionMcpServersLoadedEvent.java @@ -0,0 +1,85 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The {@code session.mcp_servers_loaded} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionMcpServersLoadedEvent extends SessionEvent { + + @Override + public String getType() { return "session.mcp_servers_loaded"; } + + @JsonProperty("data") + private SessionMcpServersLoadedEventData data; + + public SessionMcpServersLoadedEventData getData() { return data; } + public void setData(SessionMcpServersLoadedEventData data) { this.data = data; } + + /** Data payload for {@link SessionMcpServersLoadedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionMcpServersLoadedEventData( + /** Array of MCP server status summaries */ + @JsonProperty("servers") List servers + ) { + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionMcpServersLoadedEventDataServersItem( + /** Server name (config key) */ + @JsonProperty("name") String name, + /** Connection status: connected, failed, needs-auth, pending, disabled, or not_configured */ + @JsonProperty("status") SessionMcpServersLoadedEventDataServersItemStatus status, + /** Configuration source: user, workspace, plugin, or builtin */ + @JsonProperty("source") String source, + /** Error message if the server failed to connect */ + @JsonProperty("error") String error + ) { + + /** Connection status: connected, failed, needs-auth, pending, disabled, or not_configured */ + public enum SessionMcpServersLoadedEventDataServersItemStatus { + /** The {@code connected} variant. */ + CONNECTED("connected"), + /** The {@code failed} variant. */ + FAILED("failed"), + /** The {@code needs-auth} variant. */ + NEEDS_AUTH("needs-auth"), + /** The {@code pending} variant. */ + PENDING("pending"), + /** The {@code disabled} variant. */ + DISABLED("disabled"), + /** The {@code not_configured} variant. */ + NOT_CONFIGURED("not_configured"); + + private final String value; + SessionMcpServersLoadedEventDataServersItemStatus(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionMcpServersLoadedEventDataServersItemStatus fromValue(String value) { + for (SessionMcpServersLoadedEventDataServersItemStatus v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionMcpServersLoadedEventDataServersItemStatus value: " + value); + } + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionModeChangedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionModeChangedEvent.java new file mode 100644 index 000000000..82ae9ff39 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionModeChangedEvent.java @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.mode_changed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionModeChangedEvent extends SessionEvent { + + @Override + public String getType() { return "session.mode_changed"; } + + @JsonProperty("data") + private SessionModeChangedEventData data; + + public SessionModeChangedEventData getData() { return data; } + public void setData(SessionModeChangedEventData data) { this.data = data; } + + /** Data payload for {@link SessionModeChangedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionModeChangedEventData( + /** Agent mode before the change (e.g., "interactive", "plan", "autopilot") */ + @JsonProperty("previousMode") String previousMode, + /** Agent mode after the change (e.g., "interactive", "plan", "autopilot") */ + @JsonProperty("newMode") String newMode + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionModelChangeEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionModelChangeEvent.java new file mode 100644 index 000000000..c23c8a5f5 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionModelChangeEvent.java @@ -0,0 +1,48 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.model_change} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionModelChangeEvent extends SessionEvent { + + @Override + public String getType() { return "session.model_change"; } + + @JsonProperty("data") + private SessionModelChangeEventData data; + + public SessionModelChangeEventData getData() { return data; } + public void setData(SessionModelChangeEventData data) { this.data = data; } + + /** Data payload for {@link SessionModelChangeEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionModelChangeEventData( + /** Model that was previously selected, if any */ + @JsonProperty("previousModel") String previousModel, + /** Newly selected model identifier */ + @JsonProperty("newModel") String newModel, + /** Reasoning effort level before the model change, if applicable */ + @JsonProperty("previousReasoningEffort") String previousReasoningEffort, + /** Reasoning effort level after the model change, if applicable */ + @JsonProperty("reasoningEffort") String reasoningEffort + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionPlanChangedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionPlanChangedEvent.java new file mode 100644 index 000000000..0ea80289a --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionPlanChangedEvent.java @@ -0,0 +1,64 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.plan_changed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionPlanChangedEvent extends SessionEvent { + + @Override + public String getType() { return "session.plan_changed"; } + + @JsonProperty("data") + private SessionPlanChangedEventData data; + + public SessionPlanChangedEventData getData() { return data; } + public void setData(SessionPlanChangedEventData data) { this.data = data; } + + /** Data payload for {@link SessionPlanChangedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionPlanChangedEventData( + /** The type of operation performed on the plan file */ + @JsonProperty("operation") SessionPlanChangedEventDataOperation operation + ) { + + /** The type of operation performed on the plan file */ + public enum SessionPlanChangedEventDataOperation { + /** The {@code create} variant. */ + CREATE("create"), + /** The {@code update} variant. */ + UPDATE("update"), + /** The {@code delete} variant. */ + DELETE("delete"); + + private final String value; + SessionPlanChangedEventDataOperation(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionPlanChangedEventDataOperation fromValue(String value) { + for (SessionPlanChangedEventDataOperation v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionPlanChangedEventDataOperation value: " + value); + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionRemoteSteerableChangedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionRemoteSteerableChangedEvent.java new file mode 100644 index 000000000..ba752f4c6 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionRemoteSteerableChangedEvent.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.remote_steerable_changed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionRemoteSteerableChangedEvent extends SessionEvent { + + @Override + public String getType() { return "session.remote_steerable_changed"; } + + @JsonProperty("data") + private SessionRemoteSteerableChangedEventData data; + + public SessionRemoteSteerableChangedEventData getData() { return data; } + public void setData(SessionRemoteSteerableChangedEventData data) { this.data = data; } + + /** Data payload for {@link SessionRemoteSteerableChangedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionRemoteSteerableChangedEventData( + /** Whether this session now supports remote steering via Mission Control */ + @JsonProperty("remoteSteerable") Boolean remoteSteerable + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionResumeEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionResumeEvent.java new file mode 100644 index 000000000..e132a1c9f --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionResumeEvent.java @@ -0,0 +1,96 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.OffsetDateTime; +import javax.annotation.processing.Generated; + +/** + * The {@code session.resume} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionResumeEvent extends SessionEvent { + + @Override + public String getType() { return "session.resume"; } + + @JsonProperty("data") + private SessionResumeEventData data; + + public SessionResumeEventData getData() { return data; } + public void setData(SessionResumeEventData data) { this.data = data; } + + /** Data payload for {@link SessionResumeEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionResumeEventData( + /** ISO 8601 timestamp when the session was resumed */ + @JsonProperty("resumeTime") OffsetDateTime resumeTime, + /** Total number of persisted events in the session at the time of resume */ + @JsonProperty("eventCount") Double eventCount, + /** Model currently selected at resume time */ + @JsonProperty("selectedModel") String selectedModel, + /** Reasoning effort level used for model calls, if applicable (e.g. "low", "medium", "high", "xhigh") */ + @JsonProperty("reasoningEffort") String reasoningEffort, + /** Updated working directory and git context at resume time */ + @JsonProperty("context") SessionResumeEventDataContext context, + /** Whether the session was already in use by another client at resume time */ + @JsonProperty("alreadyInUse") Boolean alreadyInUse, + /** Whether this session supports remote steering via Mission Control */ + @JsonProperty("remoteSteerable") Boolean remoteSteerable + ) { + + /** Updated working directory and git context at resume time */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionResumeEventDataContext( + /** Current working directory path */ + @JsonProperty("cwd") String cwd, + /** Root directory of the git repository, resolved via git rev-parse */ + @JsonProperty("gitRoot") String gitRoot, + /** Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps) */ + @JsonProperty("repository") String repository, + /** Hosting platform type of the repository (github or ado) */ + @JsonProperty("hostType") SessionResumeEventDataContextHostType hostType, + /** Current git branch name */ + @JsonProperty("branch") String branch, + /** Head commit of current git branch at session start time */ + @JsonProperty("headCommit") String headCommit, + /** Base commit of current git branch at session start time */ + @JsonProperty("baseCommit") String baseCommit + ) { + + /** Hosting platform type of the repository (github or ado) */ + public enum SessionResumeEventDataContextHostType { + /** The {@code github} variant. */ + GITHUB("github"), + /** The {@code ado} variant. */ + ADO("ado"); + + private final String value; + SessionResumeEventDataContextHostType(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionResumeEventDataContextHostType fromValue(String value) { + for (SessionResumeEventDataContextHostType v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionResumeEventDataContextHostType value: " + value); + } + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionShutdownEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionShutdownEvent.java new file mode 100644 index 000000000..929d7eb79 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionShutdownEvent.java @@ -0,0 +1,137 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The {@code session.shutdown} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionShutdownEvent extends SessionEvent { + + @Override + public String getType() { return "session.shutdown"; } + + @JsonProperty("data") + private SessionShutdownEventData data; + + public SessionShutdownEventData getData() { return data; } + public void setData(SessionShutdownEventData data) { this.data = data; } + + /** Data payload for {@link SessionShutdownEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionShutdownEventData( + /** Whether the session ended normally ("routine") or due to a crash/fatal error ("error") */ + @JsonProperty("shutdownType") SessionShutdownEventDataShutdownType shutdownType, + /** Error description when shutdownType is "error" */ + @JsonProperty("errorReason") String errorReason, + /** Total number of premium API requests used during the session */ + @JsonProperty("totalPremiumRequests") Double totalPremiumRequests, + /** Cumulative time spent in API calls during the session, in milliseconds */ + @JsonProperty("totalApiDurationMs") Double totalApiDurationMs, + /** Unix timestamp (milliseconds) when the session started */ + @JsonProperty("sessionStartTime") Double sessionStartTime, + /** Aggregate code change metrics for the session */ + @JsonProperty("codeChanges") SessionShutdownEventDataCodeChanges codeChanges, + /** Per-model usage breakdown, keyed by model identifier */ + @JsonProperty("modelMetrics") Map modelMetrics, + /** Model that was selected at the time of shutdown */ + @JsonProperty("currentModel") String currentModel, + /** Total tokens in context window at shutdown */ + @JsonProperty("currentTokens") Double currentTokens, + /** System message token count at shutdown */ + @JsonProperty("systemTokens") Double systemTokens, + /** Non-system message token count at shutdown */ + @JsonProperty("conversationTokens") Double conversationTokens, + /** Tool definitions token count at shutdown */ + @JsonProperty("toolDefinitionsTokens") Double toolDefinitionsTokens + ) { + + /** Whether the session ended normally ("routine") or due to a crash/fatal error ("error") */ + public enum SessionShutdownEventDataShutdownType { + /** The {@code routine} variant. */ + ROUTINE("routine"), + /** The {@code error} variant. */ + ERROR("error"); + + private final String value; + SessionShutdownEventDataShutdownType(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionShutdownEventDataShutdownType fromValue(String value) { + for (SessionShutdownEventDataShutdownType v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionShutdownEventDataShutdownType value: " + value); + } + } + + /** Aggregate code change metrics for the session */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionShutdownEventDataCodeChanges( + /** Total number of lines added during the session */ + @JsonProperty("linesAdded") Double linesAdded, + /** Total number of lines removed during the session */ + @JsonProperty("linesRemoved") Double linesRemoved, + /** List of file paths that were modified during the session */ + @JsonProperty("filesModified") List filesModified + ) { + } + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionShutdownEventDataModelMetricsValue( + /** Request count and cost metrics */ + @JsonProperty("requests") SessionShutdownEventDataModelMetricsValueRequests requests, + /** Token usage breakdown */ + @JsonProperty("usage") SessionShutdownEventDataModelMetricsValueUsage usage + ) { + + /** Request count and cost metrics */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionShutdownEventDataModelMetricsValueRequests( + /** Total number of API requests made to this model */ + @JsonProperty("count") Double count, + /** Cumulative cost multiplier for requests to this model */ + @JsonProperty("cost") Double cost + ) { + } + + /** Token usage breakdown */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionShutdownEventDataModelMetricsValueUsage( + /** Total input tokens consumed across all requests to this model */ + @JsonProperty("inputTokens") Double inputTokens, + /** Total output tokens produced across all requests to this model */ + @JsonProperty("outputTokens") Double outputTokens, + /** Total tokens read from prompt cache across all requests */ + @JsonProperty("cacheReadTokens") Double cacheReadTokens, + /** Total tokens written to prompt cache across all requests */ + @JsonProperty("cacheWriteTokens") Double cacheWriteTokens, + /** Total reasoning tokens produced across all requests to this model */ + @JsonProperty("reasoningTokens") Double reasoningTokens + ) { + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionSkillsLoadedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionSkillsLoadedEvent.java new file mode 100644 index 000000000..e1a2857cd --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionSkillsLoadedEvent.java @@ -0,0 +1,61 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The {@code session.skills_loaded} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionSkillsLoadedEvent extends SessionEvent { + + @Override + public String getType() { return "session.skills_loaded"; } + + @JsonProperty("data") + private SessionSkillsLoadedEventData data; + + public SessionSkillsLoadedEventData getData() { return data; } + public void setData(SessionSkillsLoadedEventData data) { this.data = data; } + + /** Data payload for {@link SessionSkillsLoadedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionSkillsLoadedEventData( + /** Array of resolved skill metadata */ + @JsonProperty("skills") List skills + ) { + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionSkillsLoadedEventDataSkillsItem( + /** Unique identifier for the skill */ + @JsonProperty("name") String name, + /** Description of what the skill does */ + @JsonProperty("description") String description, + /** Source location type of the skill (e.g., project, personal, plugin) */ + @JsonProperty("source") String source, + /** Whether the skill can be invoked by the user as a slash command */ + @JsonProperty("userInvocable") Boolean userInvocable, + /** Whether the skill is currently enabled */ + @JsonProperty("enabled") Boolean enabled, + /** Absolute path to the skill file, if available */ + @JsonProperty("path") String path + ) { + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionSnapshotRewindEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionSnapshotRewindEvent.java new file mode 100644 index 000000000..8842827fb --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionSnapshotRewindEvent.java @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.snapshot_rewind} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionSnapshotRewindEvent extends SessionEvent { + + @Override + public String getType() { return "session.snapshot_rewind"; } + + @JsonProperty("data") + private SessionSnapshotRewindEventData data; + + public SessionSnapshotRewindEventData getData() { return data; } + public void setData(SessionSnapshotRewindEventData data) { this.data = data; } + + /** Data payload for {@link SessionSnapshotRewindEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionSnapshotRewindEventData( + /** Event ID that was rewound to; this event and all after it were removed */ + @JsonProperty("upToEventId") String upToEventId, + /** Number of events that were removed by the rewind */ + @JsonProperty("eventsRemoved") Double eventsRemoved + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionStartEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionStartEvent.java new file mode 100644 index 000000000..2db2d3fe7 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionStartEvent.java @@ -0,0 +1,102 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.OffsetDateTime; +import javax.annotation.processing.Generated; + +/** + * The {@code session.start} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionStartEvent extends SessionEvent { + + @Override + public String getType() { return "session.start"; } + + @JsonProperty("data") + private SessionStartEventData data; + + public SessionStartEventData getData() { return data; } + public void setData(SessionStartEventData data) { this.data = data; } + + /** Data payload for {@link SessionStartEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionStartEventData( + /** Unique identifier for the session */ + @JsonProperty("sessionId") String sessionId, + /** Schema version number for the session event format */ + @JsonProperty("version") Double version, + /** Identifier of the software producing the events (e.g., "copilot-agent") */ + @JsonProperty("producer") String producer, + /** Version string of the Copilot application */ + @JsonProperty("copilotVersion") String copilotVersion, + /** ISO 8601 timestamp when the session was created */ + @JsonProperty("startTime") OffsetDateTime startTime, + /** Model selected at session creation time, if any */ + @JsonProperty("selectedModel") String selectedModel, + /** Reasoning effort level used for model calls, if applicable (e.g. "low", "medium", "high", "xhigh") */ + @JsonProperty("reasoningEffort") String reasoningEffort, + /** Working directory and git context at session start */ + @JsonProperty("context") SessionStartEventDataContext context, + /** Whether the session was already in use by another client at start time */ + @JsonProperty("alreadyInUse") Boolean alreadyInUse, + /** Whether this session supports remote steering via Mission Control */ + @JsonProperty("remoteSteerable") Boolean remoteSteerable + ) { + + /** Working directory and git context at session start */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionStartEventDataContext( + /** Current working directory path */ + @JsonProperty("cwd") String cwd, + /** Root directory of the git repository, resolved via git rev-parse */ + @JsonProperty("gitRoot") String gitRoot, + /** Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps) */ + @JsonProperty("repository") String repository, + /** Hosting platform type of the repository (github or ado) */ + @JsonProperty("hostType") SessionStartEventDataContextHostType hostType, + /** Current git branch name */ + @JsonProperty("branch") String branch, + /** Head commit of current git branch at session start time */ + @JsonProperty("headCommit") String headCommit, + /** Base commit of current git branch at session start time */ + @JsonProperty("baseCommit") String baseCommit + ) { + + /** Hosting platform type of the repository (github or ado) */ + public enum SessionStartEventDataContextHostType { + /** The {@code github} variant. */ + GITHUB("github"), + /** The {@code ado} variant. */ + ADO("ado"); + + private final String value; + SessionStartEventDataContextHostType(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionStartEventDataContextHostType fromValue(String value) { + for (SessionStartEventDataContextHostType v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionStartEventDataContextHostType value: " + value); + } + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionTaskCompleteEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionTaskCompleteEvent.java new file mode 100644 index 000000000..1af7e699b --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionTaskCompleteEvent.java @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.task_complete} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionTaskCompleteEvent extends SessionEvent { + + @Override + public String getType() { return "session.task_complete"; } + + @JsonProperty("data") + private SessionTaskCompleteEventData data; + + public SessionTaskCompleteEventData getData() { return data; } + public void setData(SessionTaskCompleteEventData data) { this.data = data; } + + /** Data payload for {@link SessionTaskCompleteEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionTaskCompleteEventData( + /** Summary of the completed task, provided by the agent */ + @JsonProperty("summary") String summary, + /** Whether the tool call succeeded. False when validation failed (e.g., invalid arguments) */ + @JsonProperty("success") Boolean success + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionTitleChangedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionTitleChangedEvent.java new file mode 100644 index 000000000..309330188 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionTitleChangedEvent.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.title_changed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionTitleChangedEvent extends SessionEvent { + + @Override + public String getType() { return "session.title_changed"; } + + @JsonProperty("data") + private SessionTitleChangedEventData data; + + public SessionTitleChangedEventData getData() { return data; } + public void setData(SessionTitleChangedEventData data) { this.data = data; } + + /** Data payload for {@link SessionTitleChangedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionTitleChangedEventData( + /** The new display title for the session */ + @JsonProperty("title") String title + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionToolsUpdatedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionToolsUpdatedEvent.java new file mode 100644 index 000000000..a3b5313cf --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionToolsUpdatedEvent.java @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.tools_updated} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionToolsUpdatedEvent extends SessionEvent { + + @Override + public String getType() { return "session.tools_updated"; } + + @JsonProperty("data") + private SessionToolsUpdatedEventData data; + + public SessionToolsUpdatedEventData getData() { return data; } + public void setData(SessionToolsUpdatedEventData data) { this.data = data; } + + /** Data payload for {@link SessionToolsUpdatedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionToolsUpdatedEventData( + @JsonProperty("model") String model + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionTruncationEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionTruncationEvent.java new file mode 100644 index 000000000..103d1d017 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionTruncationEvent.java @@ -0,0 +1,56 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.truncation} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionTruncationEvent extends SessionEvent { + + @Override + public String getType() { return "session.truncation"; } + + @JsonProperty("data") + private SessionTruncationEventData data; + + public SessionTruncationEventData getData() { return data; } + public void setData(SessionTruncationEventData data) { this.data = data; } + + /** Data payload for {@link SessionTruncationEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionTruncationEventData( + /** Maximum token count for the model's context window */ + @JsonProperty("tokenLimit") Double tokenLimit, + /** Total tokens in conversation messages before truncation */ + @JsonProperty("preTruncationTokensInMessages") Double preTruncationTokensInMessages, + /** Number of conversation messages before truncation */ + @JsonProperty("preTruncationMessagesLength") Double preTruncationMessagesLength, + /** Total tokens in conversation messages after truncation */ + @JsonProperty("postTruncationTokensInMessages") Double postTruncationTokensInMessages, + /** Number of conversation messages after truncation */ + @JsonProperty("postTruncationMessagesLength") Double postTruncationMessagesLength, + /** Number of tokens removed by truncation */ + @JsonProperty("tokensRemovedDuringTruncation") Double tokensRemovedDuringTruncation, + /** Number of messages removed by truncation */ + @JsonProperty("messagesRemovedDuringTruncation") Double messagesRemovedDuringTruncation, + /** Identifier of the component that performed truncation (e.g., "BasicTruncator") */ + @JsonProperty("performedBy") String performedBy + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionUsageInfoEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionUsageInfoEvent.java new file mode 100644 index 000000000..f83c36024 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionUsageInfoEvent.java @@ -0,0 +1,54 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.usage_info} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionUsageInfoEvent extends SessionEvent { + + @Override + public String getType() { return "session.usage_info"; } + + @JsonProperty("data") + private SessionUsageInfoEventData data; + + public SessionUsageInfoEventData getData() { return data; } + public void setData(SessionUsageInfoEventData data) { this.data = data; } + + /** Data payload for {@link SessionUsageInfoEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionUsageInfoEventData( + /** Maximum token count for the model's context window */ + @JsonProperty("tokenLimit") Double tokenLimit, + /** Current number of tokens in the context window */ + @JsonProperty("currentTokens") Double currentTokens, + /** Current number of messages in the conversation */ + @JsonProperty("messagesLength") Double messagesLength, + /** Token count from system message(s) */ + @JsonProperty("systemTokens") Double systemTokens, + /** Token count from non-system messages (user, assistant, tool) */ + @JsonProperty("conversationTokens") Double conversationTokens, + /** Token count from tool definitions */ + @JsonProperty("toolDefinitionsTokens") Double toolDefinitionsTokens, + /** Whether this is the first usage_info event emitted in this session */ + @JsonProperty("isInitial") Boolean isInitial + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionWarningEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionWarningEvent.java new file mode 100644 index 000000000..1870a26e8 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionWarningEvent.java @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.warning} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionWarningEvent extends SessionEvent { + + @Override + public String getType() { return "session.warning"; } + + @JsonProperty("data") + private SessionWarningEventData data; + + public SessionWarningEventData getData() { return data; } + public void setData(SessionWarningEventData data) { this.data = data; } + + /** Data payload for {@link SessionWarningEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionWarningEventData( + /** Category of warning (e.g., "subscription", "policy", "mcp") */ + @JsonProperty("warningType") String warningType, + /** Human-readable warning message for display in the timeline */ + @JsonProperty("message") String message, + /** Optional URL associated with this warning that the user can open in a browser */ + @JsonProperty("url") String url + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SessionWorkspaceFileChangedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SessionWorkspaceFileChangedEvent.java new file mode 100644 index 000000000..ea2245adf --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SessionWorkspaceFileChangedEvent.java @@ -0,0 +1,64 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code session.workspace_file_changed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionWorkspaceFileChangedEvent extends SessionEvent { + + @Override + public String getType() { return "session.workspace_file_changed"; } + + @JsonProperty("data") + private SessionWorkspaceFileChangedEventData data; + + public SessionWorkspaceFileChangedEventData getData() { return data; } + public void setData(SessionWorkspaceFileChangedEventData data) { this.data = data; } + + /** Data payload for {@link SessionWorkspaceFileChangedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionWorkspaceFileChangedEventData( + /** Relative path within the session workspace files directory */ + @JsonProperty("path") String path, + /** Whether the file was newly created or updated */ + @JsonProperty("operation") SessionWorkspaceFileChangedEventDataOperation operation + ) { + + /** Whether the file was newly created or updated */ + public enum SessionWorkspaceFileChangedEventDataOperation { + /** The {@code create} variant. */ + CREATE("create"), + /** The {@code update} variant. */ + UPDATE("update"); + + private final String value; + SessionWorkspaceFileChangedEventDataOperation(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionWorkspaceFileChangedEventDataOperation fromValue(String value) { + for (SessionWorkspaceFileChangedEventDataOperation v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionWorkspaceFileChangedEventDataOperation value: " + value); + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SkillInvokedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SkillInvokedEvent.java new file mode 100644 index 000000000..e6c696eb0 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SkillInvokedEvent.java @@ -0,0 +1,55 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The {@code skill.invoked} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SkillInvokedEvent extends SessionEvent { + + @Override + public String getType() { return "skill.invoked"; } + + @JsonProperty("data") + private SkillInvokedEventData data; + + public SkillInvokedEventData getData() { return data; } + public void setData(SkillInvokedEventData data) { this.data = data; } + + /** Data payload for {@link SkillInvokedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SkillInvokedEventData( + /** Name of the invoked skill */ + @JsonProperty("name") String name, + /** File path to the SKILL.md definition */ + @JsonProperty("path") String path, + /** Full content of the skill file, injected into the conversation for the model */ + @JsonProperty("content") String content, + /** Tool names that should be auto-approved when this skill is active */ + @JsonProperty("allowedTools") List allowedTools, + /** Name of the plugin this skill originated from, when applicable */ + @JsonProperty("pluginName") String pluginName, + /** Version of the plugin this skill originated from, when applicable */ + @JsonProperty("pluginVersion") String pluginVersion, + /** Description of the skill from its SKILL.md frontmatter */ + @JsonProperty("description") String description + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SubagentCompletedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SubagentCompletedEvent.java new file mode 100644 index 000000000..b2cce20c3 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SubagentCompletedEvent.java @@ -0,0 +1,54 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code subagent.completed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SubagentCompletedEvent extends SessionEvent { + + @Override + public String getType() { return "subagent.completed"; } + + @JsonProperty("data") + private SubagentCompletedEventData data; + + public SubagentCompletedEventData getData() { return data; } + public void setData(SubagentCompletedEventData data) { this.data = data; } + + /** Data payload for {@link SubagentCompletedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SubagentCompletedEventData( + /** Tool call ID of the parent tool invocation that spawned this sub-agent */ + @JsonProperty("toolCallId") String toolCallId, + /** Internal name of the sub-agent */ + @JsonProperty("agentName") String agentName, + /** Human-readable display name of the sub-agent */ + @JsonProperty("agentDisplayName") String agentDisplayName, + /** Model used by the sub-agent */ + @JsonProperty("model") String model, + /** Total number of tool calls made by the sub-agent */ + @JsonProperty("totalToolCalls") Double totalToolCalls, + /** Total tokens (input + output) consumed by the sub-agent */ + @JsonProperty("totalTokens") Double totalTokens, + /** Wall-clock duration of the sub-agent execution in milliseconds */ + @JsonProperty("durationMs") Double durationMs + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SubagentDeselectedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SubagentDeselectedEvent.java new file mode 100644 index 000000000..3db9429db --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SubagentDeselectedEvent.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code subagent.deselected} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SubagentDeselectedEvent extends SessionEvent { + + @Override + public String getType() { return "subagent.deselected"; } + + @JsonProperty("data") + private SubagentDeselectedEventData data; + + public SubagentDeselectedEventData getData() { return data; } + public void setData(SubagentDeselectedEventData data) { this.data = data; } + + /** Data payload for {@link SubagentDeselectedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SubagentDeselectedEventData() { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SubagentFailedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SubagentFailedEvent.java new file mode 100644 index 000000000..490532fc3 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SubagentFailedEvent.java @@ -0,0 +1,56 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code subagent.failed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SubagentFailedEvent extends SessionEvent { + + @Override + public String getType() { return "subagent.failed"; } + + @JsonProperty("data") + private SubagentFailedEventData data; + + public SubagentFailedEventData getData() { return data; } + public void setData(SubagentFailedEventData data) { this.data = data; } + + /** Data payload for {@link SubagentFailedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SubagentFailedEventData( + /** Tool call ID of the parent tool invocation that spawned this sub-agent */ + @JsonProperty("toolCallId") String toolCallId, + /** Internal name of the sub-agent */ + @JsonProperty("agentName") String agentName, + /** Human-readable display name of the sub-agent */ + @JsonProperty("agentDisplayName") String agentDisplayName, + /** Error message describing why the sub-agent failed */ + @JsonProperty("error") String error, + /** Model used by the sub-agent (if any model calls succeeded before failure) */ + @JsonProperty("model") String model, + /** Total number of tool calls made before the sub-agent failed */ + @JsonProperty("totalToolCalls") Double totalToolCalls, + /** Total tokens (input + output) consumed before the sub-agent failed */ + @JsonProperty("totalTokens") Double totalTokens, + /** Wall-clock duration of the sub-agent execution in milliseconds */ + @JsonProperty("durationMs") Double durationMs + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SubagentSelectedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SubagentSelectedEvent.java new file mode 100644 index 000000000..e910bc9c2 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SubagentSelectedEvent.java @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The {@code subagent.selected} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SubagentSelectedEvent extends SessionEvent { + + @Override + public String getType() { return "subagent.selected"; } + + @JsonProperty("data") + private SubagentSelectedEventData data; + + public SubagentSelectedEventData getData() { return data; } + public void setData(SubagentSelectedEventData data) { this.data = data; } + + /** Data payload for {@link SubagentSelectedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SubagentSelectedEventData( + /** Internal name of the selected custom agent */ + @JsonProperty("agentName") String agentName, + /** Human-readable display name of the selected custom agent */ + @JsonProperty("agentDisplayName") String agentDisplayName, + /** List of tool names available to this agent, or null for all tools */ + @JsonProperty("tools") List tools + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SubagentStartedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SubagentStartedEvent.java new file mode 100644 index 000000000..6e9926bd4 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SubagentStartedEvent.java @@ -0,0 +1,48 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code subagent.started} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SubagentStartedEvent extends SessionEvent { + + @Override + public String getType() { return "subagent.started"; } + + @JsonProperty("data") + private SubagentStartedEventData data; + + public SubagentStartedEventData getData() { return data; } + public void setData(SubagentStartedEventData data) { this.data = data; } + + /** Data payload for {@link SubagentStartedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SubagentStartedEventData( + /** Tool call ID of the parent tool invocation that spawned this sub-agent */ + @JsonProperty("toolCallId") String toolCallId, + /** Internal name of the sub-agent */ + @JsonProperty("agentName") String agentName, + /** Human-readable display name of the sub-agent */ + @JsonProperty("agentDisplayName") String agentDisplayName, + /** Description of what the sub-agent does */ + @JsonProperty("agentDescription") String agentDescription + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SystemMessageEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SystemMessageEvent.java new file mode 100644 index 000000000..8df24f3a6 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SystemMessageEvent.java @@ -0,0 +1,80 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The {@code system.message} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SystemMessageEvent extends SessionEvent { + + @Override + public String getType() { return "system.message"; } + + @JsonProperty("data") + private SystemMessageEventData data; + + public SystemMessageEventData getData() { return data; } + public void setData(SystemMessageEventData data) { this.data = data; } + + /** Data payload for {@link SystemMessageEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SystemMessageEventData( + /** The system or developer prompt text */ + @JsonProperty("content") String content, + /** Message role: "system" for system prompts, "developer" for developer-injected instructions */ + @JsonProperty("role") SystemMessageEventDataRole role, + /** Optional name identifier for the message source */ + @JsonProperty("name") String name, + /** Metadata about the prompt template and its construction */ + @JsonProperty("metadata") SystemMessageEventDataMetadata metadata + ) { + + /** Message role: "system" for system prompts, "developer" for developer-injected instructions */ + public enum SystemMessageEventDataRole { + /** The {@code system} variant. */ + SYSTEM("system"), + /** The {@code developer} variant. */ + DEVELOPER("developer"); + + private final String value; + SystemMessageEventDataRole(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SystemMessageEventDataRole fromValue(String value) { + for (SystemMessageEventDataRole v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SystemMessageEventDataRole value: " + value); + } + } + + /** Metadata about the prompt template and its construction */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SystemMessageEventDataMetadata( + /** Version identifier of the prompt template used */ + @JsonProperty("promptVersion") String promptVersion, + /** Template variables used when constructing the prompt */ + @JsonProperty("variables") Map variables + ) { + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/SystemNotificationEvent.java b/src/generated/java/com/github/copilot/sdk/generated/SystemNotificationEvent.java new file mode 100644 index 000000000..877b3db98 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/SystemNotificationEvent.java @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code system.notification} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SystemNotificationEvent extends SessionEvent { + + @Override + public String getType() { return "system.notification"; } + + @JsonProperty("data") + private SystemNotificationEventData data; + + public SystemNotificationEventData getData() { return data; } + public void setData(SystemNotificationEventData data) { this.data = data; } + + /** Data payload for {@link SystemNotificationEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SystemNotificationEventData( + /** The notification text, typically wrapped in XML tags */ + @JsonProperty("content") String content, + /** Structured metadata identifying what triggered this notification */ + @JsonProperty("kind") Object kind + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/ToolExecutionCompleteEvent.java b/src/generated/java/com/github/copilot/sdk/generated/ToolExecutionCompleteEvent.java new file mode 100644 index 000000000..41ca020ff --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/ToolExecutionCompleteEvent.java @@ -0,0 +1,84 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The {@code tool.execution_complete} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ToolExecutionCompleteEvent extends SessionEvent { + + @Override + public String getType() { return "tool.execution_complete"; } + + @JsonProperty("data") + private ToolExecutionCompleteEventData data; + + public ToolExecutionCompleteEventData getData() { return data; } + public void setData(ToolExecutionCompleteEventData data) { this.data = data; } + + /** Data payload for {@link ToolExecutionCompleteEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ToolExecutionCompleteEventData( + /** Unique identifier for the completed tool call */ + @JsonProperty("toolCallId") String toolCallId, + /** Whether the tool execution completed successfully */ + @JsonProperty("success") Boolean success, + /** Model identifier that generated this tool call */ + @JsonProperty("model") String model, + /** CAPI interaction ID for correlating this tool execution with upstream telemetry */ + @JsonProperty("interactionId") String interactionId, + /** Whether this tool call was explicitly requested by the user rather than the assistant */ + @JsonProperty("isUserRequested") Boolean isUserRequested, + /** Tool execution result on success */ + @JsonProperty("result") ToolExecutionCompleteEventDataResult result, + /** Error details when the tool execution failed */ + @JsonProperty("error") ToolExecutionCompleteEventDataError error, + /** Tool-specific telemetry data (e.g., CodeQL check counts, grep match counts) */ + @JsonProperty("toolTelemetry") Map toolTelemetry, + /** Tool call ID of the parent tool invocation when this event originates from a sub-agent */ + @JsonProperty("parentToolCallId") String parentToolCallId + ) { + + /** Tool execution result on success */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ToolExecutionCompleteEventDataResult( + /** Concise tool result text sent to the LLM for chat completion, potentially truncated for token efficiency */ + @JsonProperty("content") String content, + /** Full detailed tool result for UI/timeline display, preserving complete content such as diffs. Falls back to content when absent. */ + @JsonProperty("detailedContent") String detailedContent, + /** Structured content blocks (text, images, audio, resources) returned by the tool in their native format */ + @JsonProperty("contents") List contents + ) { + } + + /** Error details when the tool execution failed */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ToolExecutionCompleteEventDataError( + /** Human-readable error message */ + @JsonProperty("message") String message, + /** Machine-readable error code */ + @JsonProperty("code") String code + ) { + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/ToolExecutionPartialResultEvent.java b/src/generated/java/com/github/copilot/sdk/generated/ToolExecutionPartialResultEvent.java new file mode 100644 index 000000000..5fbddc5cc --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/ToolExecutionPartialResultEvent.java @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code tool.execution_partial_result} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ToolExecutionPartialResultEvent extends SessionEvent { + + @Override + public String getType() { return "tool.execution_partial_result"; } + + @JsonProperty("data") + private ToolExecutionPartialResultEventData data; + + public ToolExecutionPartialResultEventData getData() { return data; } + public void setData(ToolExecutionPartialResultEventData data) { this.data = data; } + + /** Data payload for {@link ToolExecutionPartialResultEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ToolExecutionPartialResultEventData( + /** Tool call ID this partial result belongs to */ + @JsonProperty("toolCallId") String toolCallId, + /** Incremental output chunk from the running tool */ + @JsonProperty("partialOutput") String partialOutput + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/ToolExecutionProgressEvent.java b/src/generated/java/com/github/copilot/sdk/generated/ToolExecutionProgressEvent.java new file mode 100644 index 000000000..2a77c05ff --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/ToolExecutionProgressEvent.java @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code tool.execution_progress} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ToolExecutionProgressEvent extends SessionEvent { + + @Override + public String getType() { return "tool.execution_progress"; } + + @JsonProperty("data") + private ToolExecutionProgressEventData data; + + public ToolExecutionProgressEventData getData() { return data; } + public void setData(ToolExecutionProgressEventData data) { this.data = data; } + + /** Data payload for {@link ToolExecutionProgressEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ToolExecutionProgressEventData( + /** Tool call ID this progress notification belongs to */ + @JsonProperty("toolCallId") String toolCallId, + /** Human-readable progress status message (e.g., from an MCP server) */ + @JsonProperty("progressMessage") String progressMessage + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/ToolExecutionStartEvent.java b/src/generated/java/com/github/copilot/sdk/generated/ToolExecutionStartEvent.java new file mode 100644 index 000000000..7da757286 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/ToolExecutionStartEvent.java @@ -0,0 +1,52 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code tool.execution_start} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ToolExecutionStartEvent extends SessionEvent { + + @Override + public String getType() { return "tool.execution_start"; } + + @JsonProperty("data") + private ToolExecutionStartEventData data; + + public ToolExecutionStartEventData getData() { return data; } + public void setData(ToolExecutionStartEventData data) { this.data = data; } + + /** Data payload for {@link ToolExecutionStartEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ToolExecutionStartEventData( + /** Unique identifier for this tool call */ + @JsonProperty("toolCallId") String toolCallId, + /** Name of the tool being executed */ + @JsonProperty("toolName") String toolName, + /** Arguments passed to the tool */ + @JsonProperty("arguments") Object arguments, + /** Name of the MCP server hosting this tool, when the tool is an MCP tool */ + @JsonProperty("mcpServerName") String mcpServerName, + /** Original tool name on the MCP server, when the tool is an MCP tool */ + @JsonProperty("mcpToolName") String mcpToolName, + /** Tool call ID of the parent tool invocation when this event originates from a sub-agent */ + @JsonProperty("parentToolCallId") String parentToolCallId + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/ToolUserRequestedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/ToolUserRequestedEvent.java new file mode 100644 index 000000000..ac798fd3f --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/ToolUserRequestedEvent.java @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code tool.user_requested} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ToolUserRequestedEvent extends SessionEvent { + + @Override + public String getType() { return "tool.user_requested"; } + + @JsonProperty("data") + private ToolUserRequestedEventData data; + + public ToolUserRequestedEventData getData() { return data; } + public void setData(ToolUserRequestedEventData data) { this.data = data; } + + /** Data payload for {@link ToolUserRequestedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ToolUserRequestedEventData( + /** Unique identifier for this tool call */ + @JsonProperty("toolCallId") String toolCallId, + /** Name of the tool the user wants to invoke */ + @JsonProperty("toolName") String toolName, + /** Arguments for the tool invocation */ + @JsonProperty("arguments") Object arguments + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/UnknownSessionEvent.java b/src/generated/java/com/github/copilot/sdk/generated/UnknownSessionEvent.java new file mode 100644 index 000000000..cf56b4b4f --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/UnknownSessionEvent.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Fallback for event types not yet known to this SDK version. + *

+ * {@link #getType()} returns the original type string from the JSON payload, + * preserving forward compatibility with event types introduced by newer CLI versions. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class UnknownSessionEvent extends SessionEvent { + + @JsonProperty("type") + private String type = "unknown"; + + @Override + public String getType() { return type; } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/UserInputCompletedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/UserInputCompletedEvent.java new file mode 100644 index 000000000..7b69bfd92 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/UserInputCompletedEvent.java @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The {@code user_input.completed} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class UserInputCompletedEvent extends SessionEvent { + + @Override + public String getType() { return "user_input.completed"; } + + @JsonProperty("data") + private UserInputCompletedEventData data; + + public UserInputCompletedEventData getData() { return data; } + public void setData(UserInputCompletedEventData data) { this.data = data; } + + /** Data payload for {@link UserInputCompletedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record UserInputCompletedEventData( + /** Request ID of the resolved user input request; clients should dismiss any UI for this request */ + @JsonProperty("requestId") String requestId, + /** The user's answer to the input request */ + @JsonProperty("answer") String answer, + /** Whether the answer was typed as free-form text rather than selected from choices */ + @JsonProperty("wasFreeform") Boolean wasFreeform + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/UserInputRequestedEvent.java b/src/generated/java/com/github/copilot/sdk/generated/UserInputRequestedEvent.java new file mode 100644 index 000000000..69581e20a --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/UserInputRequestedEvent.java @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The {@code user_input.requested} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class UserInputRequestedEvent extends SessionEvent { + + @Override + public String getType() { return "user_input.requested"; } + + @JsonProperty("data") + private UserInputRequestedEventData data; + + public UserInputRequestedEventData getData() { return data; } + public void setData(UserInputRequestedEventData data) { this.data = data; } + + /** Data payload for {@link UserInputRequestedEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record UserInputRequestedEventData( + /** Unique identifier for this input request; used to respond via session.respondToUserInput() */ + @JsonProperty("requestId") String requestId, + /** The question or prompt to present to the user */ + @JsonProperty("question") String question, + /** Predefined choices for the user to select from, if applicable */ + @JsonProperty("choices") List choices, + /** Whether the user can provide a free-form text response in addition to predefined choices */ + @JsonProperty("allowFreeform") Boolean allowFreeform, + /** The LLM-assigned tool call ID that triggered this request; used by remote UIs to correlate responses */ + @JsonProperty("toolCallId") String toolCallId + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/UserMessageEvent.java b/src/generated/java/com/github/copilot/sdk/generated/UserMessageEvent.java new file mode 100644 index 000000000..e3efe4088 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/UserMessageEvent.java @@ -0,0 +1,77 @@ +/*--------------------------------------------------------------------------------------------- + * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The {@code user.message} session event. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class UserMessageEvent extends SessionEvent { + + @Override + public String getType() { return "user.message"; } + + @JsonProperty("data") + private UserMessageEventData data; + + public UserMessageEventData getData() { return data; } + public void setData(UserMessageEventData data) { this.data = data; } + + /** Data payload for {@link UserMessageEvent}. */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record UserMessageEventData( + /** The user's message text as displayed in the timeline */ + @JsonProperty("content") String content, + /** Transformed version of the message sent to the model, with XML wrapping, timestamps, and other augmentations for prompt caching */ + @JsonProperty("transformedContent") String transformedContent, + /** Files, selections, or GitHub references attached to the message */ + @JsonProperty("attachments") List attachments, + /** Origin of this message, used for timeline filtering (e.g., "skill-pdf" for skill-injected messages that should be hidden from the user) */ + @JsonProperty("source") String source, + /** The agent mode that was active when this message was sent */ + @JsonProperty("agentMode") UserMessageEventDataAgentMode agentMode, + /** CAPI interaction ID for correlating this user message with its turn */ + @JsonProperty("interactionId") String interactionId + ) { + + /** The agent mode that was active when this message was sent */ + public enum UserMessageEventDataAgentMode { + /** The {@code interactive} variant. */ + INTERACTIVE("interactive"), + /** The {@code plan} variant. */ + PLAN("plan"), + /** The {@code autopilot} variant. */ + AUTOPILOT("autopilot"), + /** The {@code shell} variant. */ + SHELL("shell"); + + private final String value; + UserMessageEventDataAgentMode(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static UserMessageEventDataAgentMode fromValue(String value) { + for (UserMessageEventDataAgentMode v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown UserMessageEventDataAgentMode value: " + value); + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/AccountGetQuotaResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/AccountGetQuotaResult.java new file mode 100644 index 000000000..29ebfa7e3 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/AccountGetQuotaResult.java @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code account.getQuota} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record AccountGetQuotaResult( + /** Quota snapshots keyed by type (e.g., chat, completions, premium_interactions) */ + @JsonProperty("quotaSnapshots") Map quotaSnapshots +) { + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record AccountGetQuotaResultQuotaSnapshotsValue( + /** Number of requests included in the entitlement */ + @JsonProperty("entitlementRequests") Double entitlementRequests, + /** Number of requests used so far this period */ + @JsonProperty("usedRequests") Double usedRequests, + /** Percentage of entitlement remaining */ + @JsonProperty("remainingPercentage") Double remainingPercentage, + /** Number of overage requests made this period */ + @JsonProperty("overage") Double overage, + /** Whether pay-per-request usage is allowed when quota is exhausted */ + @JsonProperty("overageAllowedWithExhaustedQuota") Boolean overageAllowedWithExhaustedQuota, + /** Date when the quota resets (ISO 8601) */ + @JsonProperty("resetDate") String resetDate + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/McpConfigAddParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/McpConfigAddParams.java new file mode 100644 index 000000000..0f33fdcda --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/McpConfigAddParams.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code mcp.config.add} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record McpConfigAddParams( + /** Unique name for the MCP server */ + @JsonProperty("name") String name, + /** MCP server configuration (local/stdio or remote/http) */ + @JsonProperty("config") Object config +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/McpConfigListResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/McpConfigListResult.java new file mode 100644 index 000000000..1391b451c --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/McpConfigListResult.java @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code mcp.config.list} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record McpConfigListResult( + /** All MCP servers from user config, keyed by name */ + @JsonProperty("servers") Map servers +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/McpConfigRemoveParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/McpConfigRemoveParams.java new file mode 100644 index 000000000..6c24be431 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/McpConfigRemoveParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code mcp.config.remove} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record McpConfigRemoveParams( + /** Name of the MCP server to remove */ + @JsonProperty("name") String name +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/McpConfigUpdateParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/McpConfigUpdateParams.java new file mode 100644 index 000000000..327234515 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/McpConfigUpdateParams.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code mcp.config.update} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record McpConfigUpdateParams( + /** Name of the MCP server to update */ + @JsonProperty("name") String name, + /** MCP server configuration (local/stdio or remote/http) */ + @JsonProperty("config") Object config +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/McpDiscoverParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/McpDiscoverParams.java new file mode 100644 index 000000000..24d52cffc --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/McpDiscoverParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code mcp.discover} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record McpDiscoverParams( + /** Working directory used as context for discovery (e.g., plugin resolution) */ + @JsonProperty("workingDirectory") String workingDirectory +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/McpDiscoverResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/McpDiscoverResult.java new file mode 100644 index 000000000..01561b9f4 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/McpDiscoverResult.java @@ -0,0 +1,66 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code mcp.discover} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record McpDiscoverResult( + /** MCP servers discovered from all sources */ + @JsonProperty("servers") List servers +) { + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record McpDiscoverResultServersItem( + /** Server name (config key) */ + @JsonProperty("name") String name, + /** Server type: local, stdio, http, or sse */ + @JsonProperty("type") String type, + /** Configuration source */ + @JsonProperty("source") McpDiscoverResultServersItemSource source, + /** Whether the server is enabled (not in the disabled list) */ + @JsonProperty("enabled") Boolean enabled + ) { + + /** Configuration source */ + public enum McpDiscoverResultServersItemSource { + /** The {@code user} variant. */ + USER("user"), + /** The {@code workspace} variant. */ + WORKSPACE("workspace"), + /** The {@code plugin} variant. */ + PLUGIN("plugin"), + /** The {@code builtin} variant. */ + BUILTIN("builtin"); + + private final String value; + McpDiscoverResultServersItemSource(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static McpDiscoverResultServersItemSource fromValue(String value) { + for (McpDiscoverResultServersItemSource v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown McpDiscoverResultServersItemSource value: " + value); + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/ModelsListResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/ModelsListResult.java new file mode 100644 index 000000000..6b233a737 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/ModelsListResult.java @@ -0,0 +1,118 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code models.list} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ModelsListResult( + /** List of available models with full metadata */ + @JsonProperty("models") List models +) { + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ModelsListResultModelsItem( + /** Model identifier (e.g., "claude-sonnet-4.5") */ + @JsonProperty("id") String id, + /** Display name */ + @JsonProperty("name") String name, + /** Model capabilities and limits */ + @JsonProperty("capabilities") ModelsListResultModelsItemCapabilities capabilities, + /** Policy state (if applicable) */ + @JsonProperty("policy") ModelsListResultModelsItemPolicy policy, + /** Billing information */ + @JsonProperty("billing") ModelsListResultModelsItemBilling billing, + /** Supported reasoning effort levels (only present if model supports reasoning effort) */ + @JsonProperty("supportedReasoningEfforts") List supportedReasoningEfforts, + /** Default reasoning effort level (only present if model supports reasoning effort) */ + @JsonProperty("defaultReasoningEffort") String defaultReasoningEffort + ) { + + /** Model capabilities and limits */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ModelsListResultModelsItemCapabilities( + /** Feature flags indicating what the model supports */ + @JsonProperty("supports") ModelsListResultModelsItemCapabilitiesSupports supports, + /** Token limits for prompts, outputs, and context window */ + @JsonProperty("limits") ModelsListResultModelsItemCapabilitiesLimits limits + ) { + + /** Feature flags indicating what the model supports */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ModelsListResultModelsItemCapabilitiesSupports( + /** Whether this model supports vision/image input */ + @JsonProperty("vision") Boolean vision, + /** Whether this model supports reasoning effort configuration */ + @JsonProperty("reasoningEffort") Boolean reasoningEffort + ) { + } + + /** Token limits for prompts, outputs, and context window */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ModelsListResultModelsItemCapabilitiesLimits( + /** Maximum number of prompt/input tokens */ + @JsonProperty("max_prompt_tokens") Double maxPromptTokens, + /** Maximum number of output/completion tokens */ + @JsonProperty("max_output_tokens") Double maxOutputTokens, + /** Maximum total context window size in tokens */ + @JsonProperty("max_context_window_tokens") Double maxContextWindowTokens, + /** Vision-specific limits */ + @JsonProperty("vision") ModelsListResultModelsItemCapabilitiesLimitsVision vision + ) { + + /** Vision-specific limits */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ModelsListResultModelsItemCapabilitiesLimitsVision( + /** MIME types the model accepts */ + @JsonProperty("supported_media_types") List supportedMediaTypes, + /** Maximum number of images per prompt */ + @JsonProperty("max_prompt_images") Double maxPromptImages, + /** Maximum image size in bytes */ + @JsonProperty("max_prompt_image_size") Double maxPromptImageSize + ) { + } + } + } + + /** Policy state (if applicable) */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ModelsListResultModelsItemPolicy( + /** Current policy state for this model */ + @JsonProperty("state") String state, + /** Usage terms or conditions for this model */ + @JsonProperty("terms") String terms + ) { + } + + /** Billing information */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ModelsListResultModelsItemBilling( + /** Billing cost multiplier relative to the base rate */ + @JsonProperty("multiplier") Double multiplier + ) { + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/PingParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/PingParams.java new file mode 100644 index 000000000..892d5cbb2 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/PingParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code ping} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record PingParams( + /** Optional message to echo back */ + @JsonProperty("message") String message +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/PingResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/PingResult.java new file mode 100644 index 000000000..30ff8c58a --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/PingResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code ping} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record PingResult( + /** Echoed message (or default greeting) */ + @JsonProperty("message") String message, + /** Server timestamp in milliseconds */ + @JsonProperty("timestamp") Double timestamp, + /** Server protocol version number */ + @JsonProperty("protocolVersion") Double protocolVersion +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/RpcCaller.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/RpcCaller.java new file mode 100644 index 000000000..8334649bc --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/RpcCaller.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * Interface for invoking JSON-RPC methods with typed responses. + *

+ * Implementations delegate to the underlying transport layer + * (e.g., a {@code JsonRpcClient} instance). Use a method reference: + *

{@code
+ * RpcCaller caller = jsonRpcClient::invoke;
+ * }
+ * Note: because the {@code invoke} method has a type parameter, this interface cannot + * be implemented using a lambda expression — use a method reference or anonymous class. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public interface RpcCaller { + + /** + * Invokes a JSON-RPC method and returns a future for the typed response. + * + * @param the expected response type + * @param method the JSON-RPC method name + * @param params the request parameters (may be a {@code Map}, DTO record, or {@code JsonNode}) + * @param resultType the {@link Class} of the expected response type + * @return a {@link CompletableFuture} that completes with the deserialized result + */ + CompletableFuture invoke(String method, Object params, Class resultType); +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/RpcMapper.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/RpcMapper.java new file mode 100644 index 000000000..36c1f02fb --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/RpcMapper.java @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Package-private holder for the shared {@link com.fasterxml.jackson.databind.ObjectMapper} + * used by session API classes when merging {@code sessionId} into call parameters. + *

+ * {@link com.fasterxml.jackson.databind.ObjectMapper} is thread-safe and expensive to + * instantiate, so a single shared instance is used across all generated API classes. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class RpcMapper { + + static final com.fasterxml.jackson.databind.ObjectMapper INSTANCE = + new com.fasterxml.jackson.databind.ObjectMapper(); + + private RpcMapper() {} +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerAccountApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerAccountApi.java new file mode 100644 index 000000000..ecbe8a105 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerAccountApi.java @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code account} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ServerAccountApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerAccountApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Invokes {@code account.getQuota}. + * @since 1.0.0 + */ + public CompletableFuture getQuota() { + return caller.invoke("account.getQuota", java.util.Map.of(), AccountGetQuotaResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerMcpApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerMcpApi.java new file mode 100644 index 000000000..6c376d0fe --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerMcpApi.java @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code mcp} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ServerMcpApi { + + private final RpcCaller caller; + + /** API methods for the {@code mcp.config} sub-namespace. */ + public final ServerMcpConfigApi config; + + /** @param caller the RPC transport function */ + ServerMcpApi(RpcCaller caller) { + this.caller = caller; + this.config = new ServerMcpConfigApi(caller); + } + + /** + * Invokes {@code mcp.discover}. + * @since 1.0.0 + */ + public CompletableFuture discover(McpDiscoverParams params) { + return caller.invoke("mcp.discover", params, McpDiscoverResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerMcpConfigApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerMcpConfigApi.java new file mode 100644 index 000000000..0153b2baf --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerMcpConfigApi.java @@ -0,0 +1,60 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code mcp.config} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ServerMcpConfigApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerMcpConfigApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Invokes {@code mcp.config.list}. + * @since 1.0.0 + */ + public CompletableFuture list() { + return caller.invoke("mcp.config.list", java.util.Map.of(), McpConfigListResult.class); + } + + /** + * Invokes {@code mcp.config.add}. + * @since 1.0.0 + */ + public CompletableFuture add(McpConfigAddParams params) { + return caller.invoke("mcp.config.add", params, Void.class); + } + + /** + * Invokes {@code mcp.config.update}. + * @since 1.0.0 + */ + public CompletableFuture update(McpConfigUpdateParams params) { + return caller.invoke("mcp.config.update", params, Void.class); + } + + /** + * Invokes {@code mcp.config.remove}. + * @since 1.0.0 + */ + public CompletableFuture remove(McpConfigRemoveParams params) { + return caller.invoke("mcp.config.remove", params, Void.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerModelsApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerModelsApi.java new file mode 100644 index 000000000..c3f83b45c --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerModelsApi.java @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code models} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ServerModelsApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerModelsApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Invokes {@code models.list}. + * @since 1.0.0 + */ + public CompletableFuture list() { + return caller.invoke("models.list", java.util.Map.of(), ModelsListResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerRpc.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerRpc.java new file mode 100644 index 000000000..0f0e5804c --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerRpc.java @@ -0,0 +1,63 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * Typed client for server-level RPC methods. + *

+ * Provides strongly-typed access to all server-level API namespaces. + *

+ * Obtain an instance by calling {@code new ServerRpc(caller)}. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ServerRpc { + + private final RpcCaller caller; + + /** API methods for the {@code models} namespace. */ + public final ServerModelsApi models; + /** API methods for the {@code tools} namespace. */ + public final ServerToolsApi tools; + /** API methods for the {@code account} namespace. */ + public final ServerAccountApi account; + /** API methods for the {@code mcp} namespace. */ + public final ServerMcpApi mcp; + /** API methods for the {@code sessionFs} namespace. */ + public final ServerSessionFsApi sessionFs; + /** API methods for the {@code sessions} namespace. */ + public final ServerSessionsApi sessions; + + /** + * Creates a new server RPC client. + * + * @param caller the RPC transport function (e.g., {@code jsonRpcClient::invoke}) + */ + public ServerRpc(RpcCaller caller) { + this.caller = caller; + this.models = new ServerModelsApi(caller); + this.tools = new ServerToolsApi(caller); + this.account = new ServerAccountApi(caller); + this.mcp = new ServerMcpApi(caller); + this.sessionFs = new ServerSessionFsApi(caller); + this.sessions = new ServerSessionsApi(caller); + } + + /** + * Invokes {@code ping}. + * @since 1.0.0 + */ + public CompletableFuture ping(PingParams params) { + return caller.invoke("ping", params, PingResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerSessionFsApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerSessionFsApi.java new file mode 100644 index 000000000..068ff939f --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerSessionFsApi.java @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code sessionFs} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ServerSessionFsApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerSessionFsApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Invokes {@code sessionFs.setProvider}. + * @since 1.0.0 + */ + public CompletableFuture setProvider(SessionFsSetProviderParams params) { + return caller.invoke("sessionFs.setProvider", params, SessionFsSetProviderResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerSessionsApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerSessionsApi.java new file mode 100644 index 000000000..6d1aa0651 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerSessionsApi.java @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code sessions} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ServerSessionsApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerSessionsApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Invokes {@code sessions.fork}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture fork(SessionsForkParams params) { + return caller.invoke("sessions.fork", params, SessionsForkResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerToolsApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerToolsApi.java new file mode 100644 index 000000000..2eb2a90f5 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/ServerToolsApi.java @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code tools} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ServerToolsApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerToolsApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Invokes {@code tools.list}. + * @since 1.0.0 + */ + public CompletableFuture list(ToolsListParams params) { + return caller.invoke("tools.list", params, ToolsListResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentApi.java new file mode 100644 index 000000000..068589915 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentApi.java @@ -0,0 +1,84 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code agent} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionAgentApi { + + private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = RpcMapper.INSTANCE; + + private final RpcCaller caller; + private final String sessionId; + + /** @param caller the RPC transport function */ + SessionAgentApi(RpcCaller caller, String sessionId) { + this.caller = caller; + this.sessionId = sessionId; + } + + /** + * Invokes {@code session.agent.list}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture list() { + return caller.invoke("session.agent.list", java.util.Map.of("sessionId", this.sessionId), SessionAgentListResult.class); + } + + /** + * Invokes {@code session.agent.getCurrent}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture getCurrent() { + return caller.invoke("session.agent.getCurrent", java.util.Map.of("sessionId", this.sessionId), SessionAgentGetCurrentResult.class); + } + + /** + * Invokes {@code session.agent.select}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture select(SessionAgentSelectParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.agent.select", _p, SessionAgentSelectResult.class); + } + + /** + * Invokes {@code session.agent.deselect}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture deselect() { + return caller.invoke("session.agent.deselect", java.util.Map.of("sessionId", this.sessionId), Void.class); + } + + /** + * Invokes {@code session.agent.reload}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture reload() { + return caller.invoke("session.agent.reload", java.util.Map.of("sessionId", this.sessionId), SessionAgentReloadResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentDeselectParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentDeselectParams.java new file mode 100644 index 000000000..cd101194c --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentDeselectParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.agent.deselect} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionAgentDeselectParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentDeselectResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentDeselectResult.java new file mode 100644 index 000000000..81e2e3ebb --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentDeselectResult.java @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.agent.deselect} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionAgentDeselectResult() { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentGetCurrentParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentGetCurrentParams.java new file mode 100644 index 000000000..c05e5fa36 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentGetCurrentParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.agent.getCurrent} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionAgentGetCurrentParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentGetCurrentResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentGetCurrentResult.java new file mode 100644 index 000000000..b26fa1bbb --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentGetCurrentResult.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.agent.getCurrent} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionAgentGetCurrentResult( + /** Currently selected custom agent, or null if using the default agent */ + @JsonProperty("agent") SessionAgentGetCurrentResultAgent agent +) { + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionAgentGetCurrentResultAgent( + /** Unique identifier of the custom agent */ + @JsonProperty("name") String name, + /** Human-readable display name */ + @JsonProperty("displayName") String displayName, + /** Description of the agent's purpose */ + @JsonProperty("description") String description + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentListParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentListParams.java new file mode 100644 index 000000000..e14ae40c0 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentListParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.agent.list} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionAgentListParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentListResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentListResult.java new file mode 100644 index 000000000..98bff9a15 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentListResult.java @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.agent.list} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionAgentListResult( + /** Available custom agents */ + @JsonProperty("agents") List agents +) { + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionAgentListResultAgentsItem( + /** Unique identifier of the custom agent */ + @JsonProperty("name") String name, + /** Human-readable display name */ + @JsonProperty("displayName") String displayName, + /** Description of the agent's purpose */ + @JsonProperty("description") String description + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentReloadParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentReloadParams.java new file mode 100644 index 000000000..ea1b4050b --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentReloadParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.agent.reload} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionAgentReloadParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentReloadResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentReloadResult.java new file mode 100644 index 000000000..2b1d7395a --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentReloadResult.java @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.agent.reload} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionAgentReloadResult( + /** Reloaded custom agents */ + @JsonProperty("agents") List agents +) { + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionAgentReloadResultAgentsItem( + /** Unique identifier of the custom agent */ + @JsonProperty("name") String name, + /** Human-readable display name */ + @JsonProperty("displayName") String displayName, + /** Description of the agent's purpose */ + @JsonProperty("description") String description + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentSelectParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentSelectParams.java new file mode 100644 index 000000000..61777dde3 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentSelectParams.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.agent.select} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionAgentSelectParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Name of the custom agent to select */ + @JsonProperty("name") String name +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentSelectResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentSelectResult.java new file mode 100644 index 000000000..2eff0778e --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentSelectResult.java @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.agent.select} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionAgentSelectResult( + /** The newly selected custom agent */ + @JsonProperty("agent") SessionAgentSelectResultAgent agent +) { + + /** The newly selected custom agent */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionAgentSelectResultAgent( + /** Unique identifier of the custom agent */ + @JsonProperty("name") String name, + /** Human-readable display name */ + @JsonProperty("displayName") String displayName, + /** Description of the agent's purpose */ + @JsonProperty("description") String description + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsApi.java new file mode 100644 index 000000000..8240ea871 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsApi.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code commands} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionCommandsApi { + + private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = RpcMapper.INSTANCE; + + private final RpcCaller caller; + private final String sessionId; + + /** @param caller the RPC transport function */ + SessionCommandsApi(RpcCaller caller, String sessionId) { + this.caller = caller; + this.sessionId = sessionId; + } + + /** + * Invokes {@code session.commands.handlePendingCommand}. + * @since 1.0.0 + */ + public CompletableFuture handlePendingCommand(SessionCommandsHandlePendingCommandParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.commands.handlePendingCommand", _p, SessionCommandsHandlePendingCommandResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsHandlePendingCommandParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsHandlePendingCommandParams.java new file mode 100644 index 000000000..e14d29486 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsHandlePendingCommandParams.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.commands.handlePendingCommand} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionCommandsHandlePendingCommandParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Request ID from the command invocation event */ + @JsonProperty("requestId") String requestId, + /** Error message if the command handler failed */ + @JsonProperty("error") String error +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsHandlePendingCommandResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsHandlePendingCommandResult.java new file mode 100644 index 000000000..8c79beaae --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsHandlePendingCommandResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.commands.handlePendingCommand} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionCommandsHandlePendingCommandResult( + /** Whether the command was handled successfully */ + @JsonProperty("success") Boolean success +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsApi.java new file mode 100644 index 000000000..7c5ef452a --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsApi.java @@ -0,0 +1,76 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code extensions} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionExtensionsApi { + + private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = RpcMapper.INSTANCE; + + private final RpcCaller caller; + private final String sessionId; + + /** @param caller the RPC transport function */ + SessionExtensionsApi(RpcCaller caller, String sessionId) { + this.caller = caller; + this.sessionId = sessionId; + } + + /** + * Invokes {@code session.extensions.list}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture list() { + return caller.invoke("session.extensions.list", java.util.Map.of("sessionId", this.sessionId), SessionExtensionsListResult.class); + } + + /** + * Invokes {@code session.extensions.enable}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture enable(SessionExtensionsEnableParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.extensions.enable", _p, Void.class); + } + + /** + * Invokes {@code session.extensions.disable}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture disable(SessionExtensionsDisableParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.extensions.disable", _p, Void.class); + } + + /** + * Invokes {@code session.extensions.reload}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture reload() { + return caller.invoke("session.extensions.reload", java.util.Map.of("sessionId", this.sessionId), Void.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsDisableParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsDisableParams.java new file mode 100644 index 000000000..35d68997b --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsDisableParams.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.extensions.disable} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionExtensionsDisableParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Source-qualified extension ID to disable */ + @JsonProperty("id") String id +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsDisableResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsDisableResult.java new file mode 100644 index 000000000..136e858fb --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsDisableResult.java @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.extensions.disable} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionExtensionsDisableResult() { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsEnableParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsEnableParams.java new file mode 100644 index 000000000..1161a7a73 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsEnableParams.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.extensions.enable} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionExtensionsEnableParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Source-qualified extension ID to enable */ + @JsonProperty("id") String id +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsEnableResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsEnableResult.java new file mode 100644 index 000000000..1b7d328e0 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsEnableResult.java @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.extensions.enable} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionExtensionsEnableResult() { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsListParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsListParams.java new file mode 100644 index 000000000..340153ca1 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsListParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.extensions.list} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionExtensionsListParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsListResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsListResult.java new file mode 100644 index 000000000..0f6e91d82 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsListResult.java @@ -0,0 +1,88 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.extensions.list} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionExtensionsListResult( + /** Discovered extensions and their current status */ + @JsonProperty("extensions") List extensions +) { + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionExtensionsListResultExtensionsItem( + /** Source-qualified ID (e.g., 'project:my-ext', 'user:auth-helper') */ + @JsonProperty("id") String id, + /** Extension name (directory name) */ + @JsonProperty("name") String name, + /** Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/) */ + @JsonProperty("source") SessionExtensionsListResultExtensionsItemSource source, + /** Current status: running, disabled, failed, or starting */ + @JsonProperty("status") SessionExtensionsListResultExtensionsItemStatus status, + /** Process ID if the extension is running */ + @JsonProperty("pid") Long pid + ) { + + /** Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/) */ + public enum SessionExtensionsListResultExtensionsItemSource { + /** The {@code project} variant. */ + PROJECT("project"), + /** The {@code user} variant. */ + USER("user"); + + private final String value; + SessionExtensionsListResultExtensionsItemSource(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionExtensionsListResultExtensionsItemSource fromValue(String value) { + for (SessionExtensionsListResultExtensionsItemSource v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionExtensionsListResultExtensionsItemSource value: " + value); + } + } + + /** Current status: running, disabled, failed, or starting */ + public enum SessionExtensionsListResultExtensionsItemStatus { + /** The {@code running} variant. */ + RUNNING("running"), + /** The {@code disabled} variant. */ + DISABLED("disabled"), + /** The {@code failed} variant. */ + FAILED("failed"), + /** The {@code starting} variant. */ + STARTING("starting"); + + private final String value; + SessionExtensionsListResultExtensionsItemStatus(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionExtensionsListResultExtensionsItemStatus fromValue(String value) { + for (SessionExtensionsListResultExtensionsItemStatus v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionExtensionsListResultExtensionsItemStatus value: " + value); + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsReloadParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsReloadParams.java new file mode 100644 index 000000000..36d157841 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsReloadParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.extensions.reload} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionExtensionsReloadParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsReloadResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsReloadResult.java new file mode 100644 index 000000000..e4a1a2264 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsReloadResult.java @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.extensions.reload} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionExtensionsReloadResult() { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFleetApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFleetApi.java new file mode 100644 index 000000000..8eb7558f5 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFleetApi.java @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code fleet} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionFleetApi { + + private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = RpcMapper.INSTANCE; + + private final RpcCaller caller; + private final String sessionId; + + /** @param caller the RPC transport function */ + SessionFleetApi(RpcCaller caller, String sessionId) { + this.caller = caller; + this.sessionId = sessionId; + } + + /** + * Invokes {@code session.fleet.start}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture start(SessionFleetStartParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.fleet.start", _p, SessionFleetStartResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFleetStartParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFleetStartParams.java new file mode 100644 index 000000000..871239460 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFleetStartParams.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.fleet.start} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionFleetStartParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Optional user prompt to combine with fleet instructions */ + @JsonProperty("prompt") String prompt +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFleetStartResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFleetStartResult.java new file mode 100644 index 000000000..a52813aa0 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFleetStartResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.fleet.start} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionFleetStartResult( + /** Whether fleet mode was successfully activated */ + @JsonProperty("started") Boolean started +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsAppendFileParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsAppendFileParams.java new file mode 100644 index 000000000..f50b670ee --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsAppendFileParams.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code sessionFs.appendFile} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionFsAppendFileParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Path using SessionFs conventions */ + @JsonProperty("path") String path, + /** Content to append */ + @JsonProperty("content") String content, + /** Optional POSIX-style mode for newly created files */ + @JsonProperty("mode") Double mode +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsExistsParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsExistsParams.java new file mode 100644 index 000000000..c59031c57 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsExistsParams.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code sessionFs.exists} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionFsExistsParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Path using SessionFs conventions */ + @JsonProperty("path") String path +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsExistsResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsExistsResult.java new file mode 100644 index 000000000..882207465 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsExistsResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code sessionFs.exists} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionFsExistsResult( + /** Whether the path exists */ + @JsonProperty("exists") Boolean exists +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsMkdirParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsMkdirParams.java new file mode 100644 index 000000000..53fc35f25 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsMkdirParams.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code sessionFs.mkdir} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionFsMkdirParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Path using SessionFs conventions */ + @JsonProperty("path") String path, + /** Create parent directories as needed */ + @JsonProperty("recursive") Boolean recursive, + /** Optional POSIX-style mode for newly created directories */ + @JsonProperty("mode") Double mode +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReadFileParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReadFileParams.java new file mode 100644 index 000000000..f1cad41ed --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReadFileParams.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code sessionFs.readFile} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionFsReadFileParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Path using SessionFs conventions */ + @JsonProperty("path") String path +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReadFileResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReadFileResult.java new file mode 100644 index 000000000..c03673538 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReadFileResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code sessionFs.readFile} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionFsReadFileResult( + /** File content as UTF-8 string */ + @JsonProperty("content") String content +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReaddirParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReaddirParams.java new file mode 100644 index 000000000..e3f09c370 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReaddirParams.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code sessionFs.readdir} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionFsReaddirParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Path using SessionFs conventions */ + @JsonProperty("path") String path +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReaddirResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReaddirResult.java new file mode 100644 index 000000000..3079b9813 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReaddirResult.java @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code sessionFs.readdir} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionFsReaddirResult( + /** Entry names in the directory */ + @JsonProperty("entries") List entries +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReaddirWithTypesParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReaddirWithTypesParams.java new file mode 100644 index 000000000..533dbb416 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReaddirWithTypesParams.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code sessionFs.readdirWithTypes} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionFsReaddirWithTypesParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Path using SessionFs conventions */ + @JsonProperty("path") String path +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReaddirWithTypesResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReaddirWithTypesResult.java new file mode 100644 index 000000000..0e8dc3587 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsReaddirWithTypesResult.java @@ -0,0 +1,58 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code sessionFs.readdirWithTypes} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionFsReaddirWithTypesResult( + /** Directory entries with type information */ + @JsonProperty("entries") List entries +) { + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionFsReaddirWithTypesResultEntriesItem( + /** Entry name */ + @JsonProperty("name") String name, + /** Entry type */ + @JsonProperty("type") SessionFsReaddirWithTypesResultEntriesItemType type + ) { + + /** Entry type */ + public enum SessionFsReaddirWithTypesResultEntriesItemType { + /** The {@code file} variant. */ + FILE("file"), + /** The {@code directory} variant. */ + DIRECTORY("directory"); + + private final String value; + SessionFsReaddirWithTypesResultEntriesItemType(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionFsReaddirWithTypesResultEntriesItemType fromValue(String value) { + for (SessionFsReaddirWithTypesResultEntriesItemType v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionFsReaddirWithTypesResultEntriesItemType value: " + value); + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsRenameParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsRenameParams.java new file mode 100644 index 000000000..6a18e80df --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsRenameParams.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code sessionFs.rename} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionFsRenameParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Source path using SessionFs conventions */ + @JsonProperty("src") String src, + /** Destination path using SessionFs conventions */ + @JsonProperty("dest") String dest +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsRmParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsRmParams.java new file mode 100644 index 000000000..50661a58e --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsRmParams.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code sessionFs.rm} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionFsRmParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Path using SessionFs conventions */ + @JsonProperty("path") String path, + /** Remove directories and their contents recursively */ + @JsonProperty("recursive") Boolean recursive, + /** Ignore errors if the path does not exist */ + @JsonProperty("force") Boolean force +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsSetProviderParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsSetProviderParams.java new file mode 100644 index 000000000..bbab3b934 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsSetProviderParams.java @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code sessionFs.setProvider} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionFsSetProviderParams( + /** Initial working directory for sessions */ + @JsonProperty("initialCwd") String initialCwd, + /** Path within each session's SessionFs where the runtime stores files for that session */ + @JsonProperty("sessionStatePath") String sessionStatePath, + /** Path conventions used by this filesystem */ + @JsonProperty("conventions") SessionFsSetProviderParamsConventions conventions +) { + + /** Path conventions used by this filesystem */ + public enum SessionFsSetProviderParamsConventions { + /** The {@code windows} variant. */ + WINDOWS("windows"), + /** The {@code posix} variant. */ + POSIX("posix"); + + private final String value; + SessionFsSetProviderParamsConventions(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionFsSetProviderParamsConventions fromValue(String value) { + for (SessionFsSetProviderParamsConventions v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionFsSetProviderParamsConventions value: " + value); + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsSetProviderResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsSetProviderResult.java new file mode 100644 index 000000000..dcda9e587 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsSetProviderResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code sessionFs.setProvider} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionFsSetProviderResult( + /** Whether the provider was set successfully */ + @JsonProperty("success") Boolean success +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsStatParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsStatParams.java new file mode 100644 index 000000000..5d60281c8 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsStatParams.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code sessionFs.stat} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionFsStatParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Path using SessionFs conventions */ + @JsonProperty("path") String path +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsStatResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsStatResult.java new file mode 100644 index 000000000..39b40a913 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsStatResult.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code sessionFs.stat} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionFsStatResult( + /** Whether the path is a file */ + @JsonProperty("isFile") Boolean isFile, + /** Whether the path is a directory */ + @JsonProperty("isDirectory") Boolean isDirectory, + /** File size in bytes */ + @JsonProperty("size") Double size, + /** ISO 8601 timestamp of last modification */ + @JsonProperty("mtime") String mtime, + /** ISO 8601 timestamp of creation */ + @JsonProperty("birthtime") String birthtime +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsWriteFileParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsWriteFileParams.java new file mode 100644 index 000000000..02e1dea77 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFsWriteFileParams.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code sessionFs.writeFile} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionFsWriteFileParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Path using SessionFs conventions */ + @JsonProperty("path") String path, + /** Content to write */ + @JsonProperty("content") String content, + /** Optional POSIX-style mode for newly created files */ + @JsonProperty("mode") Double mode +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryApi.java new file mode 100644 index 000000000..ed0014b71 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryApi.java @@ -0,0 +1,54 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code history} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionHistoryApi { + + private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = RpcMapper.INSTANCE; + + private final RpcCaller caller; + private final String sessionId; + + /** @param caller the RPC transport function */ + SessionHistoryApi(RpcCaller caller, String sessionId) { + this.caller = caller; + this.sessionId = sessionId; + } + + /** + * Invokes {@code session.history.compact}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture compact() { + return caller.invoke("session.history.compact", java.util.Map.of("sessionId", this.sessionId), SessionHistoryCompactResult.class); + } + + /** + * Invokes {@code session.history.truncate}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture truncate(SessionHistoryTruncateParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.history.truncate", _p, SessionHistoryTruncateResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryCompactParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryCompactParams.java new file mode 100644 index 000000000..4b352cc62 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryCompactParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.history.compact} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionHistoryCompactParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryCompactResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryCompactResult.java new file mode 100644 index 000000000..b20e2c449 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryCompactResult.java @@ -0,0 +1,52 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.history.compact} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionHistoryCompactResult( + /** Whether compaction completed successfully */ + @JsonProperty("success") Boolean success, + /** Number of tokens freed by compaction */ + @JsonProperty("tokensRemoved") Double tokensRemoved, + /** Number of messages removed during compaction */ + @JsonProperty("messagesRemoved") Double messagesRemoved, + /** Post-compaction context window usage breakdown */ + @JsonProperty("contextWindow") SessionHistoryCompactResultContextWindow contextWindow +) { + + /** Post-compaction context window usage breakdown */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionHistoryCompactResultContextWindow( + /** Maximum token count for the model's context window */ + @JsonProperty("tokenLimit") Double tokenLimit, + /** Current total tokens in the context window (system + conversation + tool definitions) */ + @JsonProperty("currentTokens") Double currentTokens, + /** Current number of messages in the conversation */ + @JsonProperty("messagesLength") Double messagesLength, + /** Token count from system message(s) */ + @JsonProperty("systemTokens") Double systemTokens, + /** Token count from non-system messages (user, assistant, tool) */ + @JsonProperty("conversationTokens") Double conversationTokens, + /** Token count from tool definitions */ + @JsonProperty("toolDefinitionsTokens") Double toolDefinitionsTokens + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryTruncateParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryTruncateParams.java new file mode 100644 index 000000000..09ddf68df --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryTruncateParams.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.history.truncate} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionHistoryTruncateParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Event ID to truncate to. This event and all events after it are removed from the session. */ + @JsonProperty("eventId") String eventId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryTruncateResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryTruncateResult.java new file mode 100644 index 000000000..65f71d4c8 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryTruncateResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.history.truncate} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionHistoryTruncateResult( + /** Number of events that were removed */ + @JsonProperty("eventsRemoved") Double eventsRemoved +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionLogParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionLogParams.java new file mode 100644 index 000000000..c87fb78eb --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionLogParams.java @@ -0,0 +1,57 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.log} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionLogParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Human-readable message */ + @JsonProperty("message") String message, + /** Log severity level. Determines how the message is displayed in the timeline. Defaults to "info". */ + @JsonProperty("level") SessionLogParamsLevel level, + /** When true, the message is transient and not persisted to the session event log on disk */ + @JsonProperty("ephemeral") Boolean ephemeral, + /** Optional URL the user can open in their browser for more details */ + @JsonProperty("url") String url +) { + + /** Log severity level. Determines how the message is displayed in the timeline. Defaults to "info". */ + public enum SessionLogParamsLevel { + /** The {@code info} variant. */ + INFO("info"), + /** The {@code warning} variant. */ + WARNING("warning"), + /** The {@code error} variant. */ + ERROR("error"); + + private final String value; + SessionLogParamsLevel(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionLogParamsLevel fromValue(String value) { + for (SessionLogParamsLevel v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionLogParamsLevel value: " + value); + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionLogResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionLogResult.java new file mode 100644 index 000000000..7ba330dac --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionLogResult.java @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.UUID; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.log} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionLogResult( + /** The unique identifier of the emitted session event */ + @JsonProperty("eventId") UUID eventId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpApi.java new file mode 100644 index 000000000..a492c1e0c --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpApi.java @@ -0,0 +1,76 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code mcp} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionMcpApi { + + private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = RpcMapper.INSTANCE; + + private final RpcCaller caller; + private final String sessionId; + + /** @param caller the RPC transport function */ + SessionMcpApi(RpcCaller caller, String sessionId) { + this.caller = caller; + this.sessionId = sessionId; + } + + /** + * Invokes {@code session.mcp.list}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture list() { + return caller.invoke("session.mcp.list", java.util.Map.of("sessionId", this.sessionId), SessionMcpListResult.class); + } + + /** + * Invokes {@code session.mcp.enable}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture enable(SessionMcpEnableParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.mcp.enable", _p, Void.class); + } + + /** + * Invokes {@code session.mcp.disable}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture disable(SessionMcpDisableParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.mcp.disable", _p, Void.class); + } + + /** + * Invokes {@code session.mcp.reload}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture reload() { + return caller.invoke("session.mcp.reload", java.util.Map.of("sessionId", this.sessionId), Void.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpDisableParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpDisableParams.java new file mode 100644 index 000000000..ab0892a9c --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpDisableParams.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.mcp.disable} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionMcpDisableParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Name of the MCP server to disable */ + @JsonProperty("serverName") String serverName +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpDisableResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpDisableResult.java new file mode 100644 index 000000000..0565cf8d1 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpDisableResult.java @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.mcp.disable} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionMcpDisableResult() { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpEnableParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpEnableParams.java new file mode 100644 index 000000000..0e6b1cf74 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpEnableParams.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.mcp.enable} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionMcpEnableParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Name of the MCP server to enable */ + @JsonProperty("serverName") String serverName +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpEnableResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpEnableResult.java new file mode 100644 index 000000000..43319c3a9 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpEnableResult.java @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.mcp.enable} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionMcpEnableResult() { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpListParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpListParams.java new file mode 100644 index 000000000..c3a8a2b8d --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpListParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.mcp.list} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionMcpListParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpListResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpListResult.java new file mode 100644 index 000000000..25f747162 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpListResult.java @@ -0,0 +1,70 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.mcp.list} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionMcpListResult( + /** Configured MCP servers */ + @JsonProperty("servers") List servers +) { + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionMcpListResultServersItem( + /** Server name (config key) */ + @JsonProperty("name") String name, + /** Connection status: connected, failed, needs-auth, pending, disabled, or not_configured */ + @JsonProperty("status") SessionMcpListResultServersItemStatus status, + /** Configuration source: user, workspace, plugin, or builtin */ + @JsonProperty("source") String source, + /** Error message if the server failed to connect */ + @JsonProperty("error") String error + ) { + + /** Connection status: connected, failed, needs-auth, pending, disabled, or not_configured */ + public enum SessionMcpListResultServersItemStatus { + /** The {@code connected} variant. */ + CONNECTED("connected"), + /** The {@code failed} variant. */ + FAILED("failed"), + /** The {@code needs-auth} variant. */ + NEEDS_AUTH("needs-auth"), + /** The {@code pending} variant. */ + PENDING("pending"), + /** The {@code disabled} variant. */ + DISABLED("disabled"), + /** The {@code not_configured} variant. */ + NOT_CONFIGURED("not_configured"); + + private final String value; + SessionMcpListResultServersItemStatus(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionMcpListResultServersItemStatus fromValue(String value) { + for (SessionMcpListResultServersItemStatus v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionMcpListResultServersItemStatus value: " + value); + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpReloadParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpReloadParams.java new file mode 100644 index 000000000..b3e3ccf28 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpReloadParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.mcp.reload} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionMcpReloadParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpReloadResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpReloadResult.java new file mode 100644 index 000000000..80a2c4c26 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpReloadResult.java @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.mcp.reload} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionMcpReloadResult() { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeApi.java new file mode 100644 index 000000000..dc04fdb74 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeApi.java @@ -0,0 +1,50 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code mode} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionModeApi { + + private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = RpcMapper.INSTANCE; + + private final RpcCaller caller; + private final String sessionId; + + /** @param caller the RPC transport function */ + SessionModeApi(RpcCaller caller, String sessionId) { + this.caller = caller; + this.sessionId = sessionId; + } + + /** + * Invokes {@code session.mode.get}. + * @since 1.0.0 + */ + public CompletableFuture get() { + return caller.invoke("session.mode.get", java.util.Map.of("sessionId", this.sessionId), SessionModeGetResult.class); + } + + /** + * Invokes {@code session.mode.set}. + * @since 1.0.0 + */ + public CompletableFuture set(SessionModeSetParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.mode.set", _p, SessionModeSetResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeGetParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeGetParams.java new file mode 100644 index 000000000..e62ab01d6 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeGetParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.mode.get} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionModeGetParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeGetResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeGetResult.java new file mode 100644 index 000000000..595dff851 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeGetResult.java @@ -0,0 +1,49 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.mode.get} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionModeGetResult( + /** The current agent mode. */ + @JsonProperty("mode") SessionModeGetResultMode mode +) { + + /** The current agent mode. */ + public enum SessionModeGetResultMode { + /** The {@code interactive} variant. */ + INTERACTIVE("interactive"), + /** The {@code plan} variant. */ + PLAN("plan"), + /** The {@code autopilot} variant. */ + AUTOPILOT("autopilot"); + + private final String value; + SessionModeGetResultMode(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionModeGetResultMode fromValue(String value) { + for (SessionModeGetResultMode v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionModeGetResultMode value: " + value); + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeSetParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeSetParams.java new file mode 100644 index 000000000..dfbae5cac --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeSetParams.java @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.mode.set} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionModeSetParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** The mode to switch to. Valid values: "interactive", "plan", "autopilot". */ + @JsonProperty("mode") SessionModeSetParamsMode mode +) { + + /** The mode to switch to. Valid values: "interactive", "plan", "autopilot". */ + public enum SessionModeSetParamsMode { + /** The {@code interactive} variant. */ + INTERACTIVE("interactive"), + /** The {@code plan} variant. */ + PLAN("plan"), + /** The {@code autopilot} variant. */ + AUTOPILOT("autopilot"); + + private final String value; + SessionModeSetParamsMode(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionModeSetParamsMode fromValue(String value) { + for (SessionModeSetParamsMode v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionModeSetParamsMode value: " + value); + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeSetResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeSetResult.java new file mode 100644 index 000000000..f4609f671 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeSetResult.java @@ -0,0 +1,49 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.mode.set} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionModeSetResult( + /** The agent mode after switching. */ + @JsonProperty("mode") SessionModeSetResultMode mode +) { + + /** The agent mode after switching. */ + public enum SessionModeSetResultMode { + /** The {@code interactive} variant. */ + INTERACTIVE("interactive"), + /** The {@code plan} variant. */ + PLAN("plan"), + /** The {@code autopilot} variant. */ + AUTOPILOT("autopilot"); + + private final String value; + SessionModeSetResultMode(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionModeSetResultMode fromValue(String value) { + for (SessionModeSetResultMode v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionModeSetResultMode value: " + value); + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelApi.java new file mode 100644 index 000000000..c1de6c619 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelApi.java @@ -0,0 +1,50 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code model} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionModelApi { + + private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = RpcMapper.INSTANCE; + + private final RpcCaller caller; + private final String sessionId; + + /** @param caller the RPC transport function */ + SessionModelApi(RpcCaller caller, String sessionId) { + this.caller = caller; + this.sessionId = sessionId; + } + + /** + * Invokes {@code session.model.getCurrent}. + * @since 1.0.0 + */ + public CompletableFuture getCurrent() { + return caller.invoke("session.model.getCurrent", java.util.Map.of("sessionId", this.sessionId), SessionModelGetCurrentResult.class); + } + + /** + * Invokes {@code session.model.switchTo}. + * @since 1.0.0 + */ + public CompletableFuture switchTo(SessionModelSwitchToParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.model.switchTo", _p, SessionModelSwitchToResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelGetCurrentParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelGetCurrentParams.java new file mode 100644 index 000000000..e49e4f2df --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelGetCurrentParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.model.getCurrent} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionModelGetCurrentParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelGetCurrentResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelGetCurrentResult.java new file mode 100644 index 000000000..7467fd4e8 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelGetCurrentResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.model.getCurrent} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionModelGetCurrentResult( + /** Currently active model identifier */ + @JsonProperty("modelId") String modelId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelSwitchToParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelSwitchToParams.java new file mode 100644 index 000000000..994b3f53b --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelSwitchToParams.java @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.model.switchTo} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionModelSwitchToParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Model identifier to switch to */ + @JsonProperty("modelId") String modelId, + /** Reasoning effort level to use for the model */ + @JsonProperty("reasoningEffort") String reasoningEffort, + /** Override individual model capabilities resolved by the runtime */ + @JsonProperty("modelCapabilities") SessionModelSwitchToParamsModelCapabilities modelCapabilities +) { + + /** Override individual model capabilities resolved by the runtime */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionModelSwitchToParamsModelCapabilities( + /** Feature flags indicating what the model supports */ + @JsonProperty("supports") SessionModelSwitchToParamsModelCapabilitiesSupports supports, + /** Token limits for prompts, outputs, and context window */ + @JsonProperty("limits") SessionModelSwitchToParamsModelCapabilitiesLimits limits + ) { + + /** Feature flags indicating what the model supports */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionModelSwitchToParamsModelCapabilitiesSupports( + @JsonProperty("vision") Boolean vision, + @JsonProperty("reasoningEffort") Boolean reasoningEffort + ) { + } + + /** Token limits for prompts, outputs, and context window */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionModelSwitchToParamsModelCapabilitiesLimits( + @JsonProperty("max_prompt_tokens") Double maxPromptTokens, + @JsonProperty("max_output_tokens") Double maxOutputTokens, + /** Maximum total context window size in tokens */ + @JsonProperty("max_context_window_tokens") Double maxContextWindowTokens, + @JsonProperty("vision") SessionModelSwitchToParamsModelCapabilitiesLimitsVision vision + ) { + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionModelSwitchToParamsModelCapabilitiesLimitsVision( + /** MIME types the model accepts */ + @JsonProperty("supported_media_types") List supportedMediaTypes, + /** Maximum number of images per prompt */ + @JsonProperty("max_prompt_images") Double maxPromptImages, + /** Maximum image size in bytes */ + @JsonProperty("max_prompt_image_size") Double maxPromptImageSize + ) { + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelSwitchToResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelSwitchToResult.java new file mode 100644 index 000000000..5e93b51ae --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelSwitchToResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.model.switchTo} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionModelSwitchToResult( + /** Currently active model identifier after the switch */ + @JsonProperty("modelId") String modelId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsApi.java new file mode 100644 index 000000000..a0faf0414 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsApi.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code permissions} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionPermissionsApi { + + private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = RpcMapper.INSTANCE; + + private final RpcCaller caller; + private final String sessionId; + + /** @param caller the RPC transport function */ + SessionPermissionsApi(RpcCaller caller, String sessionId) { + this.caller = caller; + this.sessionId = sessionId; + } + + /** + * Invokes {@code session.permissions.handlePendingPermissionRequest}. + * @since 1.0.0 + */ + public CompletableFuture handlePendingPermissionRequest(SessionPermissionsHandlePendingPermissionRequestParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.permissions.handlePendingPermissionRequest", _p, SessionPermissionsHandlePendingPermissionRequestResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsHandlePendingPermissionRequestParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsHandlePendingPermissionRequestParams.java new file mode 100644 index 000000000..016d2001c --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsHandlePendingPermissionRequestParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.permissions.handlePendingPermissionRequest} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionPermissionsHandlePendingPermissionRequestParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Request ID of the pending permission request */ + @JsonProperty("requestId") String requestId, + @JsonProperty("result") Object result +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsHandlePendingPermissionRequestResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsHandlePendingPermissionRequestResult.java new file mode 100644 index 000000000..cbbdd075b --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsHandlePendingPermissionRequestResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.permissions.handlePendingPermissionRequest} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionPermissionsHandlePendingPermissionRequestResult( + /** Whether the permission request was handled successfully */ + @JsonProperty("success") Boolean success +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanApi.java new file mode 100644 index 000000000..cfd26bd1d --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanApi.java @@ -0,0 +1,58 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code plan} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionPlanApi { + + private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = RpcMapper.INSTANCE; + + private final RpcCaller caller; + private final String sessionId; + + /** @param caller the RPC transport function */ + SessionPlanApi(RpcCaller caller, String sessionId) { + this.caller = caller; + this.sessionId = sessionId; + } + + /** + * Invokes {@code session.plan.read}. + * @since 1.0.0 + */ + public CompletableFuture read() { + return caller.invoke("session.plan.read", java.util.Map.of("sessionId", this.sessionId), SessionPlanReadResult.class); + } + + /** + * Invokes {@code session.plan.update}. + * @since 1.0.0 + */ + public CompletableFuture update(SessionPlanUpdateParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.plan.update", _p, Void.class); + } + + /** + * Invokes {@code session.plan.delete}. + * @since 1.0.0 + */ + public CompletableFuture delete() { + return caller.invoke("session.plan.delete", java.util.Map.of("sessionId", this.sessionId), Void.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanDeleteParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanDeleteParams.java new file mode 100644 index 000000000..ba09c2d66 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanDeleteParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.plan.delete} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionPlanDeleteParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanDeleteResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanDeleteResult.java new file mode 100644 index 000000000..666109985 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanDeleteResult.java @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.plan.delete} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionPlanDeleteResult() { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanReadParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanReadParams.java new file mode 100644 index 000000000..23484403d --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanReadParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.plan.read} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionPlanReadParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanReadResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanReadResult.java new file mode 100644 index 000000000..ddfe1cf5c --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanReadResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.plan.read} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionPlanReadResult( + /** Whether the plan file exists in the workspace */ + @JsonProperty("exists") Boolean exists, + /** The content of the plan file, or null if it does not exist */ + @JsonProperty("content") String content, + /** Absolute file path of the plan file, or null if workspace is not enabled */ + @JsonProperty("path") String path +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanUpdateParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanUpdateParams.java new file mode 100644 index 000000000..9bd69e384 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanUpdateParams.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.plan.update} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionPlanUpdateParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** The new content for the plan file */ + @JsonProperty("content") String content +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanUpdateResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanUpdateResult.java new file mode 100644 index 000000000..aa6c64aaf --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanUpdateResult.java @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.plan.update} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionPlanUpdateResult() { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPluginsApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPluginsApi.java new file mode 100644 index 000000000..897fecd16 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPluginsApi.java @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code plugins} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionPluginsApi { + + private final RpcCaller caller; + private final String sessionId; + + /** @param caller the RPC transport function */ + SessionPluginsApi(RpcCaller caller, String sessionId) { + this.caller = caller; + this.sessionId = sessionId; + } + + /** + * Invokes {@code session.plugins.list}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture list() { + return caller.invoke("session.plugins.list", java.util.Map.of("sessionId", this.sessionId), SessionPluginsListResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPluginsListParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPluginsListParams.java new file mode 100644 index 000000000..b3407dd52 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPluginsListParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.plugins.list} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionPluginsListParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPluginsListResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPluginsListResult.java new file mode 100644 index 000000000..d6008318d --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPluginsListResult.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.plugins.list} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionPluginsListResult( + /** Installed plugins */ + @JsonProperty("plugins") List plugins +) { + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionPluginsListResultPluginsItem( + /** Plugin name */ + @JsonProperty("name") String name, + /** Marketplace the plugin came from */ + @JsonProperty("marketplace") String marketplace, + /** Installed version */ + @JsonProperty("version") String version, + /** Whether the plugin is currently enabled */ + @JsonProperty("enabled") Boolean enabled + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionRpc.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionRpc.java new file mode 100644 index 000000000..eeef86f54 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionRpc.java @@ -0,0 +1,104 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * Typed client for session-scoped RPC methods. + *

+ * Provides strongly-typed access to all session-level API namespaces. + * The {@code sessionId} is injected automatically into every call. + *

+ * Obtain an instance by calling {@code new SessionRpc(caller, sessionId)}. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionRpc { + + private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = RpcMapper.INSTANCE; + + private final RpcCaller caller; + private final String sessionId; + + /** API methods for the {@code model} namespace. */ + public final SessionModelApi model; + /** API methods for the {@code mode} namespace. */ + public final SessionModeApi mode; + /** API methods for the {@code plan} namespace. */ + public final SessionPlanApi plan; + /** API methods for the {@code workspace} namespace. */ + public final SessionWorkspaceApi workspace; + /** API methods for the {@code fleet} namespace. */ + public final SessionFleetApi fleet; + /** API methods for the {@code agent} namespace. */ + public final SessionAgentApi agent; + /** API methods for the {@code skills} namespace. */ + public final SessionSkillsApi skills; + /** API methods for the {@code mcp} namespace. */ + public final SessionMcpApi mcp; + /** API methods for the {@code plugins} namespace. */ + public final SessionPluginsApi plugins; + /** API methods for the {@code extensions} namespace. */ + public final SessionExtensionsApi extensions; + /** API methods for the {@code tools} namespace. */ + public final SessionToolsApi tools; + /** API methods for the {@code commands} namespace. */ + public final SessionCommandsApi commands; + /** API methods for the {@code ui} namespace. */ + public final SessionUiApi ui; + /** API methods for the {@code permissions} namespace. */ + public final SessionPermissionsApi permissions; + /** API methods for the {@code shell} namespace. */ + public final SessionShellApi shell; + /** API methods for the {@code history} namespace. */ + public final SessionHistoryApi history; + /** API methods for the {@code usage} namespace. */ + public final SessionUsageApi usage; + + /** + * Creates a new session RPC client. + * + * @param caller the RPC transport function (e.g., {@code jsonRpcClient::invoke}) + * @param sessionId the session ID to inject into every request + */ + public SessionRpc(RpcCaller caller, String sessionId) { + this.caller = caller; + this.sessionId = sessionId; + this.model = new SessionModelApi(caller, sessionId); + this.mode = new SessionModeApi(caller, sessionId); + this.plan = new SessionPlanApi(caller, sessionId); + this.workspace = new SessionWorkspaceApi(caller, sessionId); + this.fleet = new SessionFleetApi(caller, sessionId); + this.agent = new SessionAgentApi(caller, sessionId); + this.skills = new SessionSkillsApi(caller, sessionId); + this.mcp = new SessionMcpApi(caller, sessionId); + this.plugins = new SessionPluginsApi(caller, sessionId); + this.extensions = new SessionExtensionsApi(caller, sessionId); + this.tools = new SessionToolsApi(caller, sessionId); + this.commands = new SessionCommandsApi(caller, sessionId); + this.ui = new SessionUiApi(caller, sessionId); + this.permissions = new SessionPermissionsApi(caller, sessionId); + this.shell = new SessionShellApi(caller, sessionId); + this.history = new SessionHistoryApi(caller, sessionId); + this.usage = new SessionUsageApi(caller, sessionId); + } + + /** + * Invokes {@code session.log}. + * @since 1.0.0 + */ + public CompletableFuture log(SessionLogParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.log", _p, SessionLogResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellApi.java new file mode 100644 index 000000000..2856e213a --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellApi.java @@ -0,0 +1,52 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code shell} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionShellApi { + + private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = RpcMapper.INSTANCE; + + private final RpcCaller caller; + private final String sessionId; + + /** @param caller the RPC transport function */ + SessionShellApi(RpcCaller caller, String sessionId) { + this.caller = caller; + this.sessionId = sessionId; + } + + /** + * Invokes {@code session.shell.exec}. + * @since 1.0.0 + */ + public CompletableFuture exec(SessionShellExecParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.shell.exec", _p, SessionShellExecResult.class); + } + + /** + * Invokes {@code session.shell.kill}. + * @since 1.0.0 + */ + public CompletableFuture kill(SessionShellKillParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.shell.kill", _p, SessionShellKillResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellExecParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellExecParams.java new file mode 100644 index 000000000..9e9d93e99 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellExecParams.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.shell.exec} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionShellExecParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Shell command to execute */ + @JsonProperty("command") String command, + /** Working directory (defaults to session working directory) */ + @JsonProperty("cwd") String cwd, + /** Timeout in milliseconds (default: 30000) */ + @JsonProperty("timeout") Double timeout +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellExecResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellExecResult.java new file mode 100644 index 000000000..34288630b --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellExecResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.shell.exec} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionShellExecResult( + /** Unique identifier for tracking streamed output */ + @JsonProperty("processId") String processId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellKillParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellKillParams.java new file mode 100644 index 000000000..19569dd0e --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellKillParams.java @@ -0,0 +1,53 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.shell.kill} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionShellKillParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Process identifier returned by shell.exec */ + @JsonProperty("processId") String processId, + /** Signal to send (default: SIGTERM) */ + @JsonProperty("signal") SessionShellKillParamsSignal signal +) { + + /** Signal to send (default: SIGTERM) */ + public enum SessionShellKillParamsSignal { + /** The {@code SIGTERM} variant. */ + SIGTERM("SIGTERM"), + /** The {@code SIGKILL} variant. */ + SIGKILL("SIGKILL"), + /** The {@code SIGINT} variant. */ + SIGINT("SIGINT"); + + private final String value; + SessionShellKillParamsSignal(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionShellKillParamsSignal fromValue(String value) { + for (SessionShellKillParamsSignal v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionShellKillParamsSignal value: " + value); + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellKillResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellKillResult.java new file mode 100644 index 000000000..e786d93c4 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellKillResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.shell.kill} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionShellKillResult( + /** Whether the signal was sent successfully */ + @JsonProperty("killed") Boolean killed +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsApi.java new file mode 100644 index 000000000..6189d703a --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsApi.java @@ -0,0 +1,76 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code skills} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionSkillsApi { + + private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = RpcMapper.INSTANCE; + + private final RpcCaller caller; + private final String sessionId; + + /** @param caller the RPC transport function */ + SessionSkillsApi(RpcCaller caller, String sessionId) { + this.caller = caller; + this.sessionId = sessionId; + } + + /** + * Invokes {@code session.skills.list}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture list() { + return caller.invoke("session.skills.list", java.util.Map.of("sessionId", this.sessionId), SessionSkillsListResult.class); + } + + /** + * Invokes {@code session.skills.enable}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture enable(SessionSkillsEnableParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.skills.enable", _p, Void.class); + } + + /** + * Invokes {@code session.skills.disable}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture disable(SessionSkillsDisableParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.skills.disable", _p, Void.class); + } + + /** + * Invokes {@code session.skills.reload}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture reload() { + return caller.invoke("session.skills.reload", java.util.Map.of("sessionId", this.sessionId), Void.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsDisableParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsDisableParams.java new file mode 100644 index 000000000..163df3a0a --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsDisableParams.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.skills.disable} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionSkillsDisableParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Name of the skill to disable */ + @JsonProperty("name") String name +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsDisableResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsDisableResult.java new file mode 100644 index 000000000..7f3fe40b8 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsDisableResult.java @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.skills.disable} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionSkillsDisableResult() { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsEnableParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsEnableParams.java new file mode 100644 index 000000000..72b1944cd --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsEnableParams.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.skills.enable} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionSkillsEnableParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Name of the skill to enable */ + @JsonProperty("name") String name +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsEnableResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsEnableResult.java new file mode 100644 index 000000000..1e7ea4c7f --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsEnableResult.java @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.skills.enable} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionSkillsEnableResult() { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsListParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsListParams.java new file mode 100644 index 000000000..5575ef478 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsListParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.skills.list} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionSkillsListParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsListResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsListResult.java new file mode 100644 index 000000000..dc6ba023e --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsListResult.java @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.skills.list} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionSkillsListResult( + /** Available skills */ + @JsonProperty("skills") List skills +) { + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionSkillsListResultSkillsItem( + /** Unique identifier for the skill */ + @JsonProperty("name") String name, + /** Description of what the skill does */ + @JsonProperty("description") String description, + /** Source location type (e.g., project, personal, plugin) */ + @JsonProperty("source") String source, + /** Whether the skill can be invoked by the user as a slash command */ + @JsonProperty("userInvocable") Boolean userInvocable, + /** Whether the skill is currently enabled */ + @JsonProperty("enabled") Boolean enabled, + /** Absolute path to the skill file */ + @JsonProperty("path") String path + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsReloadParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsReloadParams.java new file mode 100644 index 000000000..664fd836a --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsReloadParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.skills.reload} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionSkillsReloadParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsReloadResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsReloadResult.java new file mode 100644 index 000000000..1bfca46e1 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsReloadResult.java @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.skills.reload} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionSkillsReloadResult() { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsApi.java new file mode 100644 index 000000000..513281198 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsApi.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code tools} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionToolsApi { + + private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = RpcMapper.INSTANCE; + + private final RpcCaller caller; + private final String sessionId; + + /** @param caller the RPC transport function */ + SessionToolsApi(RpcCaller caller, String sessionId) { + this.caller = caller; + this.sessionId = sessionId; + } + + /** + * Invokes {@code session.tools.handlePendingToolCall}. + * @since 1.0.0 + */ + public CompletableFuture handlePendingToolCall(SessionToolsHandlePendingToolCallParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.tools.handlePendingToolCall", _p, SessionToolsHandlePendingToolCallResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsHandlePendingToolCallParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsHandlePendingToolCallParams.java new file mode 100644 index 000000000..796001d8f --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsHandlePendingToolCallParams.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.tools.handlePendingToolCall} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionToolsHandlePendingToolCallParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Request ID of the pending tool call */ + @JsonProperty("requestId") String requestId, + /** Tool call result (string or expanded result object) */ + @JsonProperty("result") Object result, + /** Error message if the tool call failed */ + @JsonProperty("error") String error +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsHandlePendingToolCallResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsHandlePendingToolCallResult.java new file mode 100644 index 000000000..3f7a2acc1 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsHandlePendingToolCallResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.tools.handlePendingToolCall} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionToolsHandlePendingToolCallResult( + /** Whether the tool call result was handled successfully */ + @JsonProperty("success") Boolean success +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiApi.java new file mode 100644 index 000000000..b5eaf872e --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiApi.java @@ -0,0 +1,52 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code ui} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionUiApi { + + private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = RpcMapper.INSTANCE; + + private final RpcCaller caller; + private final String sessionId; + + /** @param caller the RPC transport function */ + SessionUiApi(RpcCaller caller, String sessionId) { + this.caller = caller; + this.sessionId = sessionId; + } + + /** + * Invokes {@code session.ui.elicitation}. + * @since 1.0.0 + */ + public CompletableFuture elicitation(SessionUiElicitationParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.ui.elicitation", _p, SessionUiElicitationResult.class); + } + + /** + * Invokes {@code session.ui.handlePendingElicitation}. + * @since 1.0.0 + */ + public CompletableFuture handlePendingElicitation(SessionUiHandlePendingElicitationParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.ui.handlePendingElicitation", _p, SessionUiHandlePendingElicitationResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiElicitationParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiElicitationParams.java new file mode 100644 index 000000000..d1df4daea --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiElicitationParams.java @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.ui.elicitation} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionUiElicitationParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Message describing what information is needed from the user */ + @JsonProperty("message") String message, + /** JSON Schema describing the form fields to present to the user */ + @JsonProperty("requestedSchema") SessionUiElicitationParamsRequestedSchema requestedSchema +) { + + /** JSON Schema describing the form fields to present to the user */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionUiElicitationParamsRequestedSchema( + /** Schema type indicator (always 'object') */ + @JsonProperty("type") String type, + /** Form field definitions, keyed by field name */ + @JsonProperty("properties") Map properties, + /** List of required field names */ + @JsonProperty("required") List required + ) { + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiElicitationResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiElicitationResult.java new file mode 100644 index 000000000..92ea41778 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiElicitationResult.java @@ -0,0 +1,52 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.ui.elicitation} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionUiElicitationResult( + /** The user's response: accept (submitted), decline (rejected), or cancel (dismissed) */ + @JsonProperty("action") SessionUiElicitationResultAction action, + /** The form values submitted by the user (present when action is 'accept') */ + @JsonProperty("content") Map content +) { + + /** The user's response: accept (submitted), decline (rejected), or cancel (dismissed) */ + public enum SessionUiElicitationResultAction { + /** The {@code accept} variant. */ + ACCEPT("accept"), + /** The {@code decline} variant. */ + DECLINE("decline"), + /** The {@code cancel} variant. */ + CANCEL("cancel"); + + private final String value; + SessionUiElicitationResultAction(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionUiElicitationResultAction fromValue(String value) { + for (SessionUiElicitationResultAction v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionUiElicitationResultAction value: " + value); + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiHandlePendingElicitationParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiHandlePendingElicitationParams.java new file mode 100644 index 000000000..e890fffbd --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiHandlePendingElicitationParams.java @@ -0,0 +1,65 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.ui.handlePendingElicitation} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionUiHandlePendingElicitationParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** The unique request ID from the elicitation.requested event */ + @JsonProperty("requestId") String requestId, + /** The elicitation response (accept with form values, decline, or cancel) */ + @JsonProperty("result") SessionUiHandlePendingElicitationParamsResult result +) { + + /** The elicitation response (accept with form values, decline, or cancel) */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionUiHandlePendingElicitationParamsResult( + /** The user's response: accept (submitted), decline (rejected), or cancel (dismissed) */ + @JsonProperty("action") SessionUiHandlePendingElicitationParamsResultAction action, + /** The form values submitted by the user (present when action is 'accept') */ + @JsonProperty("content") Map content + ) { + + /** The user's response: accept (submitted), decline (rejected), or cancel (dismissed) */ + public enum SessionUiHandlePendingElicitationParamsResultAction { + /** The {@code accept} variant. */ + ACCEPT("accept"), + /** The {@code decline} variant. */ + DECLINE("decline"), + /** The {@code cancel} variant. */ + CANCEL("cancel"); + + private final String value; + SessionUiHandlePendingElicitationParamsResultAction(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionUiHandlePendingElicitationParamsResultAction fromValue(String value) { + for (SessionUiHandlePendingElicitationParamsResultAction v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionUiHandlePendingElicitationParamsResultAction value: " + value); + } + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiHandlePendingElicitationResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiHandlePendingElicitationResult.java new file mode 100644 index 000000000..549609a87 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiHandlePendingElicitationResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.ui.handlePendingElicitation} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionUiHandlePendingElicitationResult( + /** Whether the response was accepted. False if the request was already resolved by another client. */ + @JsonProperty("success") Boolean success +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUsageApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUsageApi.java new file mode 100644 index 000000000..7b3402732 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUsageApi.java @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code usage} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionUsageApi { + + private final RpcCaller caller; + private final String sessionId; + + /** @param caller the RPC transport function */ + SessionUsageApi(RpcCaller caller, String sessionId) { + this.caller = caller; + this.sessionId = sessionId; + } + + /** + * Invokes {@code session.usage.getMetrics}. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + public CompletableFuture getMetrics() { + return caller.invoke("session.usage.getMetrics", java.util.Map.of("sessionId", this.sessionId), SessionUsageGetMetricsResult.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUsageGetMetricsParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUsageGetMetricsParams.java new file mode 100644 index 000000000..4696c7fc9 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUsageGetMetricsParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.usage.getMetrics} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionUsageGetMetricsParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUsageGetMetricsResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUsageGetMetricsResult.java new file mode 100644 index 000000000..5a98516d4 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUsageGetMetricsResult.java @@ -0,0 +1,95 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.usage.getMetrics} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionUsageGetMetricsResult( + /** Total user-initiated premium request cost across all models (may be fractional due to multipliers) */ + @JsonProperty("totalPremiumRequestCost") Double totalPremiumRequestCost, + /** Raw count of user-initiated API requests */ + @JsonProperty("totalUserRequests") Long totalUserRequests, + /** Total time spent in model API calls (milliseconds) */ + @JsonProperty("totalApiDurationMs") Double totalApiDurationMs, + /** Session start timestamp (epoch milliseconds) */ + @JsonProperty("sessionStartTime") Long sessionStartTime, + /** Aggregated code change metrics */ + @JsonProperty("codeChanges") SessionUsageGetMetricsResultCodeChanges codeChanges, + /** Per-model token and request metrics, keyed by model identifier */ + @JsonProperty("modelMetrics") Map modelMetrics, + /** Currently active model identifier */ + @JsonProperty("currentModel") String currentModel, + /** Input tokens from the most recent main-agent API call */ + @JsonProperty("lastCallInputTokens") Long lastCallInputTokens, + /** Output tokens from the most recent main-agent API call */ + @JsonProperty("lastCallOutputTokens") Long lastCallOutputTokens +) { + + /** Aggregated code change metrics */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionUsageGetMetricsResultCodeChanges( + /** Total lines of code added */ + @JsonProperty("linesAdded") Long linesAdded, + /** Total lines of code removed */ + @JsonProperty("linesRemoved") Long linesRemoved, + /** Number of distinct files modified */ + @JsonProperty("filesModifiedCount") Long filesModifiedCount + ) { + } + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionUsageGetMetricsResultModelMetricsValue( + /** Request count and cost metrics for this model */ + @JsonProperty("requests") SessionUsageGetMetricsResultModelMetricsValueRequests requests, + /** Token usage metrics for this model */ + @JsonProperty("usage") SessionUsageGetMetricsResultModelMetricsValueUsage usage + ) { + + /** Request count and cost metrics for this model */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionUsageGetMetricsResultModelMetricsValueRequests( + /** Number of API requests made with this model */ + @JsonProperty("count") Long count, + /** User-initiated premium request cost (with multiplier applied) */ + @JsonProperty("cost") Double cost + ) { + } + + /** Token usage metrics for this model */ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionUsageGetMetricsResultModelMetricsValueUsage( + /** Total input tokens consumed */ + @JsonProperty("inputTokens") Long inputTokens, + /** Total output tokens produced */ + @JsonProperty("outputTokens") Long outputTokens, + /** Total tokens read from prompt cache */ + @JsonProperty("cacheReadTokens") Long cacheReadTokens, + /** Total tokens written to prompt cache */ + @JsonProperty("cacheWriteTokens") Long cacheWriteTokens, + /** Total output tokens used for reasoning */ + @JsonProperty("reasoningTokens") Long reasoningTokens + ) { + } + } +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceApi.java new file mode 100644 index 000000000..ce6e35192 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceApi.java @@ -0,0 +1,60 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code workspace} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionWorkspaceApi { + + private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = RpcMapper.INSTANCE; + + private final RpcCaller caller; + private final String sessionId; + + /** @param caller the RPC transport function */ + SessionWorkspaceApi(RpcCaller caller, String sessionId) { + this.caller = caller; + this.sessionId = sessionId; + } + + /** + * Invokes {@code session.workspace.listFiles}. + * @since 1.0.0 + */ + public CompletableFuture listFiles() { + return caller.invoke("session.workspace.listFiles", java.util.Map.of("sessionId", this.sessionId), SessionWorkspaceListFilesResult.class); + } + + /** + * Invokes {@code session.workspace.readFile}. + * @since 1.0.0 + */ + public CompletableFuture readFile(SessionWorkspaceReadFileParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.workspace.readFile", _p, SessionWorkspaceReadFileResult.class); + } + + /** + * Invokes {@code session.workspace.createFile}. + * @since 1.0.0 + */ + public CompletableFuture createFile(SessionWorkspaceCreateFileParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.workspace.createFile", _p, Void.class); + } + +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceCreateFileParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceCreateFileParams.java new file mode 100644 index 000000000..c25fdd790 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceCreateFileParams.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.workspace.createFile} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionWorkspaceCreateFileParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Relative path within the workspace files directory */ + @JsonProperty("path") String path, + /** File content to write as a UTF-8 string */ + @JsonProperty("content") String content +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceCreateFileResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceCreateFileResult.java new file mode 100644 index 000000000..e77cf58c5 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceCreateFileResult.java @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.workspace.createFile} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionWorkspaceCreateFileResult() { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceListFilesParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceListFilesParams.java new file mode 100644 index 000000000..0fb6431c9 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceListFilesParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.workspace.listFiles} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionWorkspaceListFilesParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceListFilesResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceListFilesResult.java new file mode 100644 index 000000000..1b46df541 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceListFilesResult.java @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.workspace.listFiles} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionWorkspaceListFilesResult( + /** Relative file paths in the workspace files directory */ + @JsonProperty("files") List files +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceReadFileParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceReadFileParams.java new file mode 100644 index 000000000..ded74763a --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceReadFileParams.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.workspace.readFile} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionWorkspaceReadFileParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Relative path within the workspace files directory */ + @JsonProperty("path") String path +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceReadFileResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceReadFileResult.java new file mode 100644 index 000000000..c8705581e --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceReadFileResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code session.workspace.readFile} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionWorkspaceReadFileResult( + /** File content as a UTF-8 string */ + @JsonProperty("content") String content +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionsForkParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionsForkParams.java new file mode 100644 index 000000000..06ea46c93 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionsForkParams.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code sessions.fork} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionsForkParams( + /** Source session ID to fork from */ + @JsonProperty("sessionId") String sessionId, + /** Optional event ID boundary. When provided, the fork includes only events before this ID (exclusive). When omitted, all events are included. */ + @JsonProperty("toEventId") String toEventId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionsForkResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionsForkResult.java new file mode 100644 index 000000000..911574f56 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionsForkResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code sessions.fork} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionsForkResult( + /** The new forked session's ID */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/ToolsListParams.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/ToolsListParams.java new file mode 100644 index 000000000..2c5aa5b09 --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/ToolsListParams.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code tools.list} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ToolsListParams( + /** Optional model ID — when provided, the returned tool list reflects model-specific overrides */ + @JsonProperty("model") String model +) { +} diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/ToolsListResult.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/ToolsListResult.java new file mode 100644 index 000000000..d56ef7e7c --- /dev/null +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/ToolsListResult.java @@ -0,0 +1,45 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.sdk.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * Result for the {@code tools.list} RPC method. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ToolsListResult( + /** List of available built-in tools with metadata */ + @JsonProperty("tools") List tools +) { + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record ToolsListResultToolsItem( + /** Tool identifier (e.g., "bash", "grep", "str_replace_editor") */ + @JsonProperty("name") String name, + /** Optional namespaced name for declarative filtering (e.g., "playwright/navigate" for MCP tools) */ + @JsonProperty("namespacedName") String namespacedName, + /** Description of what the tool does */ + @JsonProperty("description") String description, + /** JSON Schema for the tool's input parameters */ + @JsonProperty("parameters") Map parameters, + /** Optional instructions for how to use this tool effectively */ + @JsonProperty("instructions") String instructions + ) { + } +} diff --git a/src/main/java/com/github/copilot/sdk/CopilotClient.java b/src/main/java/com/github/copilot/sdk/CopilotClient.java index f00e2fd11..4b3bb0904 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotClient.java +++ b/src/main/java/com/github/copilot/sdk/CopilotClient.java @@ -21,6 +21,7 @@ import com.github.copilot.sdk.json.CopilotClientOptions; import com.github.copilot.sdk.json.CreateSessionResponse; +import com.github.copilot.sdk.generated.rpc.ServerRpc; import com.github.copilot.sdk.json.DeleteSessionResponse; import com.github.copilot.sdk.json.GetAuthStatusResponse; import com.github.copilot.sdk.json.GetLastSessionIdResponse; @@ -179,7 +180,7 @@ private Connection startCoreBody() { processInfo.port()); } - Connection connection = new Connection(rpc, process); + Connection connection = new Connection(rpc, process, new ServerRpc(rpc::invoke)); // Register handlers for server-to-client calls RpcHandlerDispatcher dispatcher = new RpcHandlerDispatcher(sessions, lifecycleManager::dispatch, @@ -478,6 +479,32 @@ public ConnectionState getState() { return ConnectionState.CONNECTED; } + /** + * Returns the typed RPC client for server-level methods. + *

+ * Provides strongly-typed access to all server-level API namespaces such as + * {@code models}, {@code tools}, {@code account}, and {@code mcp}. + *

+ * Example usage: + * + *

{@code
+     * client.start().get();
+     * var models = client.getRpc().models.list().get();
+     * }
+ * + * @return the server-level typed RPC client + * @throws IllegalStateException + * if the client is not connected; call {@link #start()} first + * @since 1.0.0 + */ + public ServerRpc getRpc() { + CompletableFuture future = connectionFuture; + if (future == null || !future.isDone() || future.isCompletedExceptionally()) { + throw new IllegalStateException("Client not connected; call start() first"); + } + return future.join().serverRpc(); + } + /** * Pings the server to check connectivity. *

@@ -795,7 +822,7 @@ public void close() { } } - private static record Connection(JsonRpcClient rpc, Process process) { + private static record Connection(JsonRpcClient rpc, Process process, ServerRpc serverRpc) { }; } diff --git a/src/main/java/com/github/copilot/sdk/CopilotSession.java b/src/main/java/com/github/copilot/sdk/CopilotSession.java index 23b1b5368..a58356c2a 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotSession.java +++ b/src/main/java/com/github/copilot/sdk/CopilotSession.java @@ -29,16 +29,26 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.copilot.sdk.events.AbstractSessionEvent; -import com.github.copilot.sdk.events.AssistantMessageEvent; -import com.github.copilot.sdk.events.CapabilitiesChangedEvent; -import com.github.copilot.sdk.events.CommandExecuteEvent; -import com.github.copilot.sdk.events.ElicitationRequestedEvent; -import com.github.copilot.sdk.events.ExternalToolRequestedEvent; -import com.github.copilot.sdk.events.PermissionRequestedEvent; -import com.github.copilot.sdk.events.SessionErrorEvent; -import com.github.copilot.sdk.events.SessionEventParser; -import com.github.copilot.sdk.events.SessionIdleEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; +import com.github.copilot.sdk.generated.rpc.SessionCommandsHandlePendingCommandParams; +import com.github.copilot.sdk.generated.rpc.SessionLogParams; +import com.github.copilot.sdk.generated.rpc.SessionModelSwitchToParams; +import com.github.copilot.sdk.generated.rpc.SessionPermissionsHandlePendingPermissionRequestParams; +import com.github.copilot.sdk.generated.rpc.SessionRpc; +import com.github.copilot.sdk.generated.rpc.SessionToolsHandlePendingToolCallParams; +import com.github.copilot.sdk.generated.rpc.SessionUiElicitationParams; +import com.github.copilot.sdk.generated.rpc.SessionUiElicitationResult; +import com.github.copilot.sdk.generated.rpc.SessionUiHandlePendingElicitationParams; +import com.github.copilot.sdk.generated.rpc.SessionUiHandlePendingElicitationParams.SessionUiHandlePendingElicitationParamsResult; +import com.github.copilot.sdk.generated.rpc.SessionUiHandlePendingElicitationParams.SessionUiHandlePendingElicitationParamsResult.SessionUiHandlePendingElicitationParamsResultAction; +import com.github.copilot.sdk.generated.CapabilitiesChangedEvent; +import com.github.copilot.sdk.generated.CommandExecuteEvent; +import com.github.copilot.sdk.generated.ElicitationRequestedEvent; +import com.github.copilot.sdk.generated.ExternalToolRequestedEvent; +import com.github.copilot.sdk.generated.PermissionRequestedEvent; +import com.github.copilot.sdk.generated.SessionErrorEvent; +import com.github.copilot.sdk.generated.SessionEvent; +import com.github.copilot.sdk.generated.SessionIdleEvent; import com.github.copilot.sdk.json.AgentInfo; import com.github.copilot.sdk.json.CommandContext; import com.github.copilot.sdk.json.CommandDefinition; @@ -116,7 +126,7 @@ * @see CopilotClient#createSession(com.github.copilot.sdk.json.SessionConfig) * @see CopilotClient#resumeSession(String, * com.github.copilot.sdk.json.ResumeSessionConfig) - * @see AbstractSessionEvent + * @see SessionEvent * @since 1.0.0 */ public final class CopilotSession implements AutoCloseable { @@ -135,7 +145,8 @@ public final class CopilotSession implements AutoCloseable { private volatile SessionCapabilities capabilities = new SessionCapabilities(); private final SessionUiApi ui; private final JsonRpcClient rpc; - private final Set> eventHandlers = ConcurrentHashMap.newKeySet(); + private volatile SessionRpc sessionRpc; + private final Set> eventHandlers = ConcurrentHashMap.newKeySet(); private final Map toolHandlers = new ConcurrentHashMap<>(); private final Map commandHandlers = new ConcurrentHashMap<>(); private final AtomicReference permissionHandler = new AtomicReference<>(); @@ -220,6 +231,7 @@ public String getSessionId() { */ void setActiveSessionId(String sessionId) { this.sessionId = sessionId; + this.sessionRpc = null; // Reset so getRpc() lazily re-creates with the new sessionId } /** @@ -270,6 +282,39 @@ public SessionUiApi getUi() { return ui; } + /** + * Returns the typed RPC client for this session. + *

+ * Provides strongly-typed access to all session-level API namespaces. The + * {@code sessionId} is injected automatically into every call. + *

+ * Example usage: + * + *

{@code
+     * var agents = session.getRpc().agent.list().get();
+     * }
+ * + * @return the session-scoped typed RPC client (never {@code null}) + * @throws IllegalStateException + * if the session is not connected + * @since 1.0.0 + */ + public SessionRpc getRpc() { + if (rpc == null) { + throw new IllegalStateException("Session is not connected — RPC client is unavailable"); + } + SessionRpc current = sessionRpc; + if (current == null) { + synchronized (this) { + current = sessionRpc; + if (current == null) { + sessionRpc = current = new SessionRpc(rpc::invoke, sessionId); + } + } + } + return current; + } + /** * Sets a custom error handler for exceptions thrown by event handlers. *

@@ -450,7 +495,7 @@ public CompletableFuture sendAndWait(MessageOptions optio var future = new CompletableFuture(); var lastAssistantMessage = new AtomicReference(); - Consumer handler = evt -> { + Consumer handler = evt -> { if (evt instanceof AssistantMessageEvent msg) { lastAssistantMessage.set(msg); } else if (evt instanceof SessionIdleEvent) { @@ -563,7 +608,7 @@ public CompletableFuture sendAndWait(MessageOptions optio * *

{@code
      * // Collect all events
-     * var events = new ArrayList();
+     * var events = new ArrayList();
      * session.on(events::add);
      * }
* @@ -573,10 +618,10 @@ public CompletableFuture sendAndWait(MessageOptions optio * @throws IllegalStateException * if this session has been terminated * @see #on(Class, Consumer) - * @see AbstractSessionEvent + * @see SessionEvent * @see #setEventErrorPolicy(EventErrorPolicy) */ - public Closeable on(Consumer handler) { + public Closeable on(Consumer handler) { ensureNotTerminated(); eventHandlers.add(handler); return () -> eventHandlers.remove(handler); @@ -626,11 +671,11 @@ public Closeable on(Consumer handler) { * @throws IllegalStateException * if this session has been terminated * @see #on(Consumer) - * @see AbstractSessionEvent + * @see SessionEvent */ - public Closeable on(Class eventType, Consumer handler) { + public Closeable on(Class eventType, Consumer handler) { ensureNotTerminated(); - Consumer wrapper = event -> { + Consumer wrapper = event -> { if (eventType.isInstance(event)) { handler.accept(eventType.cast(event)); } @@ -662,12 +707,12 @@ public Closeable on(Class eventType, Consume * @see #setEventErrorHandler(EventErrorHandler) * @see #setEventErrorPolicy(EventErrorPolicy) */ - void dispatchEvent(AbstractSessionEvent event) { + void dispatchEvent(SessionEvent event) { // Handle broadcast request events (protocol v3) before dispatching to user // handlers. These are fire-and-forget: the response is sent asynchronously. handleBroadcastEventAsync(event); - for (Consumer handler : eventHandlers) { + for (Consumer handler : eventHandlers) { try { handler.accept(event); } catch (Exception e) { @@ -697,7 +742,7 @@ void dispatchEvent(AbstractSessionEvent event) { * @param event * the event to handle */ - private void handleBroadcastEventAsync(AbstractSessionEvent event) { + private void handleBroadcastEventAsync(SessionEvent event) { if (event instanceof ExternalToolRequestedEvent toolEvent) { var data = toolEvent.getData(); if (data == null || data.requestId() == null || data.toolName() == null) { @@ -721,7 +766,8 @@ private void handleBroadcastEventAsync(AbstractSessionEvent event) { if (handler == null) { return; // This client doesn't handle permissions; another client will } - executePermissionAndRespondAsync(data.requestId(), data.permissionRequest(), handler); + executePermissionAndRespondAsync(data.requestId(), + MAPPER.convertValue(data.permissionRequest(), PermissionRequest.class), handler); } else if (event instanceof CommandExecuteEvent cmdEvent) { var data = cmdEvent.getData(); if (data == null || data.requestId() == null || data.commandName() == null) { @@ -742,8 +788,8 @@ private void handleBroadcastEventAsync(AbstractSessionEvent event) { .setRequired(data.requestedSchema().required()); } var context = new ElicitationContext().setSessionId(sessionId).setMessage(data.message()) - .setRequestedSchema(schema).setMode(data.mode()).setElicitationSource(data.elicitationSource()) - .setUrl(data.url()); + .setRequestedSchema(schema).setMode(data.mode() != null ? data.mode().getValue() : null) + .setElicitationSource(data.elicitationSource()).setUrl(data.url()); handleElicitationRequestAsync(context, data.requestId()); } } else if (event instanceof CapabilitiesChangedEvent capEvent) { @@ -783,18 +829,15 @@ private void executeToolAndRespondAsync(String requestId, String toolName, Strin toolResult = ToolResultObject .success(result instanceof String s ? s : MAPPER.writeValueAsString(result)); } - rpc.invoke("session.tools.handlePendingToolCall", - Map.of("sessionId", sessionId, "requestId", requestId, "result", toolResult), - Object.class); + getRpc().tools.handlePendingToolCall( + new SessionToolsHandlePendingToolCallParams(sessionId, requestId, toolResult, null)); } catch (Exception e) { LOG.log(Level.WARNING, "Error sending tool result for requestId=" + requestId, e); } }).exceptionally(ex -> { try { - rpc.invoke( - "session.tools.handlePendingToolCall", Map.of("sessionId", sessionId, "requestId", - requestId, "error", ex.getMessage() != null ? ex.getMessage() : ex.toString()), - Object.class); + getRpc().tools.handlePendingToolCall(new SessionToolsHandlePendingToolCallParams(sessionId, + requestId, null, ex.getMessage() != null ? ex.getMessage() : ex.toString())); } catch (Exception e) { LOG.log(Level.WARNING, "Error sending tool error for requestId=" + requestId, e); } @@ -803,10 +846,8 @@ private void executeToolAndRespondAsync(String requestId, String toolName, Strin } catch (Exception e) { LOG.log(Level.WARNING, "Error executing tool for requestId=" + requestId, e); try { - rpc.invoke( - "session.tools.handlePendingToolCall", Map.of("sessionId", sessionId, "requestId", - requestId, "error", e.getMessage() != null ? e.getMessage() : e.toString()), - Object.class); + getRpc().tools.handlePendingToolCall(new SessionToolsHandlePendingToolCallParams(sessionId, + requestId, null, e.getMessage() != null ? e.getMessage() : e.toString())); } catch (Exception sendEx) { LOG.log(Level.WARNING, "Error sending tool error for requestId=" + requestId, sendEx); } @@ -824,6 +865,17 @@ private void executeToolAndRespondAsync(String requestId, String toolName, Strin } } + /** + * Builds a {@link SessionUiHandlePendingElicitationParams} carrying a + * {@code cancel} action, used when an elicitation handler throws or the handler + * future completes exceptionally. + */ + private SessionUiHandlePendingElicitationParams buildElicitationCancelParams(String requestId) { + var cancelResult = new SessionUiHandlePendingElicitationParamsResult( + SessionUiHandlePendingElicitationParamsResultAction.CANCEL, null); + return new SessionUiHandlePendingElicitationParams(sessionId, requestId, cancelResult); + } + /** * Executes a permission handler and sends the result back via * {@code session.permissions.handlePendingPermissionRequest}. @@ -842,8 +894,9 @@ private void executePermissionAndRespondAsync(String requestId, PermissionReques // so another client can handle it. return; } - rpc.invoke("session.permissions.handlePendingPermissionRequest", - Map.of("sessionId", sessionId, "requestId", requestId, "result", result), Object.class); + getRpc().permissions.handlePendingPermissionRequest( + new SessionPermissionsHandlePendingPermissionRequestParams(sessionId, requestId, + result)); } catch (Exception e) { LOG.log(Level.WARNING, "Error sending permission result for requestId=" + requestId, e); } @@ -851,8 +904,9 @@ private void executePermissionAndRespondAsync(String requestId, PermissionReques try { PermissionRequestResult denied = new PermissionRequestResult(); denied.setKind(PermissionRequestResultKind.DENIED_COULD_NOT_REQUEST_FROM_USER); - rpc.invoke("session.permissions.handlePendingPermissionRequest", - Map.of("sessionId", sessionId, "requestId", requestId, "result", denied), Object.class); + getRpc().permissions.handlePendingPermissionRequest( + new SessionPermissionsHandlePendingPermissionRequestParams(sessionId, requestId, + denied)); } catch (Exception e) { LOG.log(Level.WARNING, "Error sending permission denied for requestId=" + requestId, e); } @@ -863,8 +917,8 @@ private void executePermissionAndRespondAsync(String requestId, PermissionReques try { PermissionRequestResult denied = new PermissionRequestResult(); denied.setKind(PermissionRequestResultKind.DENIED_COULD_NOT_REQUEST_FROM_USER); - rpc.invoke("session.permissions.handlePendingPermissionRequest", - Map.of("sessionId", sessionId, "requestId", requestId, "result", denied), Object.class); + getRpc().permissions.handlePendingPermissionRequest( + new SessionPermissionsHandlePendingPermissionRequestParams(sessionId, requestId, denied)); } catch (Exception sendEx) { LOG.log(Level.WARNING, "Error sending permission denied for requestId=" + requestId, sendEx); } @@ -908,8 +962,8 @@ private void executeCommandAndRespondAsync(String requestId, String commandName, Runnable task = () -> { if (handler == null) { try { - rpc.invoke("session.commands.handlePendingCommand", Map.of("sessionId", sessionId, "requestId", - requestId, "error", "Unknown command: " + commandName), Object.class); + getRpc().commands.handlePendingCommand(new SessionCommandsHandlePendingCommandParams(sessionId, + requestId, "Unknown command: " + commandName)); } catch (Exception e) { LOG.log(Level.WARNING, "Error sending command error for requestId=" + requestId, e); } @@ -920,16 +974,16 @@ private void executeCommandAndRespondAsync(String requestId, String commandName, .setArgs(args); handler.handle(ctx).thenRun(() -> { try { - rpc.invoke("session.commands.handlePendingCommand", - Map.of("sessionId", sessionId, "requestId", requestId), Object.class); + getRpc().commands.handlePendingCommand( + new SessionCommandsHandlePendingCommandParams(sessionId, requestId, null)); } catch (Exception e) { LOG.log(Level.WARNING, "Error sending command result for requestId=" + requestId, e); } }).exceptionally(ex -> { try { String msg = ex.getMessage() != null ? ex.getMessage() : ex.toString(); - rpc.invoke("session.commands.handlePendingCommand", - Map.of("sessionId", sessionId, "requestId", requestId, "error", msg), Object.class); + getRpc().commands.handlePendingCommand( + new SessionCommandsHandlePendingCommandParams(sessionId, requestId, msg)); } catch (Exception e) { LOG.log(Level.WARNING, "Error sending command error for requestId=" + requestId, e); } @@ -939,8 +993,8 @@ private void executeCommandAndRespondAsync(String requestId, String commandName, LOG.log(Level.WARNING, "Error executing command for requestId=" + requestId, e); try { String msg = e.getMessage() != null ? e.getMessage() : e.toString(); - rpc.invoke("session.commands.handlePendingCommand", - Map.of("sessionId", sessionId, "requestId", requestId, "error", msg), Object.class); + getRpc().commands.handlePendingCommand( + new SessionCommandsHandlePendingCommandParams(sessionId, requestId, msg)); } catch (Exception sendEx) { LOG.log(Level.WARNING, "Error sending command error for requestId=" + requestId, sendEx); } @@ -974,20 +1028,17 @@ private void handleElicitationRequestAsync(ElicitationContext context, String re String actionStr = result.getAction() != null ? result.getAction().getValue() : ElicitationResultAction.CANCEL.getValue(); - Map resultMap = result.getContent() != null - ? Map.of("action", actionStr, "content", result.getContent()) - : Map.of("action", actionStr); - rpc.invoke("session.ui.handlePendingElicitation", - Map.of("sessionId", sessionId, "requestId", requestId, "result", resultMap), - Object.class); + var parsedAction = SessionUiHandlePendingElicitationParamsResultAction.fromValue(actionStr); + var elicitationResult = new SessionUiHandlePendingElicitationParamsResult(parsedAction, + result.getContent()); + getRpc().ui.handlePendingElicitation( + new SessionUiHandlePendingElicitationParams(sessionId, requestId, elicitationResult)); } catch (Exception e) { LOG.log(Level.WARNING, "Error sending elicitation result for requestId=" + requestId, e); } }).exceptionally(ex -> { try { - rpc.invoke("session.ui.handlePendingElicitation", Map.of("sessionId", sessionId, "requestId", - requestId, "result", Map.of("action", ElicitationResultAction.CANCEL.getValue())), - Object.class); + getRpc().ui.handlePendingElicitation(buildElicitationCancelParams(requestId)); } catch (Exception e) { LOG.log(Level.WARNING, "Error sending elicitation cancel for requestId=" + requestId, e); } @@ -996,10 +1047,7 @@ private void handleElicitationRequestAsync(ElicitationContext context, String re } catch (Exception e) { LOG.log(Level.WARNING, "Error executing elicitation handler for requestId=" + requestId, e); try { - rpc.invoke( - "session.ui.handlePendingElicitation", Map.of("sessionId", sessionId, "requestId", - requestId, "result", Map.of("action", ElicitationResultAction.CANCEL.getValue())), - Object.class); + getRpc().ui.handlePendingElicitation(buildElicitationCancelParams(requestId)); } catch (Exception sendEx) { LOG.log(Level.WARNING, "Error sending elicitation cancel for requestId=" + requestId, sendEx); } @@ -1037,19 +1085,15 @@ private final class SessionUiApiImpl implements SessionUiApi { @Override public CompletableFuture elicitation(ElicitationParams params) { assertElicitation(); - var schema = new java.util.HashMap(); - schema.put("type", params.getRequestedSchema().getType()); - schema.put("properties", params.getRequestedSchema().getProperties()); - if (params.getRequestedSchema().getRequired() != null) { - schema.put("required", params.getRequestedSchema().getRequired()); - } - return rpc.invoke("session.ui.elicitation", - Map.of("sessionId", sessionId, "message", params.getMessage(), "requestedSchema", schema), - ElicitationRpcResponse.class).thenApply(resp -> { + return getRpc().ui.elicitation(new SessionUiElicitationParams(sessionId, params.getMessage(), + new SessionUiElicitationParams.SessionUiElicitationParamsRequestedSchema( + params.getRequestedSchema().getType(), params.getRequestedSchema().getProperties(), + params.getRequestedSchema().getRequired()))) + .thenApply(resp -> { var result = new ElicitationResult(); if (resp.action() != null) { for (ElicitationResultAction a : ElicitationResultAction.values()) { - if (a.getValue().equalsIgnoreCase(resp.action())) { + if (a.getValue().equalsIgnoreCase(resp.action().getValue())) { result.setAction(a); break; } @@ -1067,12 +1111,14 @@ public CompletableFuture elicitation(ElicitationParams params public CompletableFuture confirm(String message) { assertElicitation(); var field = Map.of("type", "boolean", "default", (Object) true); - var schema = Map.of("type", (Object) "object", "properties", (Object) Map.of("confirmed", (Object) field), - "required", (Object) new String[]{"confirmed"}); - return rpc.invoke("session.ui.elicitation", - Map.of("sessionId", sessionId, "message", message, "requestedSchema", schema), - ElicitationRpcResponse.class).thenApply(resp -> { - if ("accept".equalsIgnoreCase(resp.action()) && resp.content() != null) { + return getRpc().ui + .elicitation( + new SessionUiElicitationParams(sessionId, message, + new SessionUiElicitationParams.SessionUiElicitationParamsRequestedSchema("object", + Map.of("confirmed", (Object) field), List.of("confirmed")))) + .thenApply(resp -> { + if (resp.action() == SessionUiElicitationResult.SessionUiElicitationResultAction.ACCEPT + && resp.content() != null) { Object val = resp.content().get("confirmed"); if (val instanceof Boolean b) { return b; @@ -1092,12 +1138,14 @@ public CompletableFuture confirm(String message) { public CompletableFuture select(String message, String[] options) { assertElicitation(); var field = Map.of("type", (Object) "string", "enum", (Object) options); - var schema = Map.of("type", (Object) "object", "properties", (Object) Map.of("selection", (Object) field), - "required", (Object) new String[]{"selection"}); - return rpc.invoke("session.ui.elicitation", - Map.of("sessionId", sessionId, "message", message, "requestedSchema", schema), - ElicitationRpcResponse.class).thenApply(resp -> { - if ("accept".equalsIgnoreCase(resp.action()) && resp.content() != null) { + return getRpc().ui + .elicitation( + new SessionUiElicitationParams(sessionId, message, + new SessionUiElicitationParams.SessionUiElicitationParamsRequestedSchema("object", + Map.of("selection", (Object) field), List.of("selection")))) + .thenApply(resp -> { + if (resp.action() == SessionUiElicitationResult.SessionUiElicitationResultAction.ACCEPT + && resp.content() != null) { Object val = resp.content().get("selection"); return val != null ? val.toString() : null; } @@ -1124,12 +1172,12 @@ public CompletableFuture input(String message, InputOptions options) { if (options.getDefaultValue() != null) field.put("default", options.getDefaultValue()); } - var schema = Map.of("type", (Object) "object", "properties", (Object) Map.of("value", (Object) field), - "required", (Object) new String[]{"value"}); - return rpc.invoke("session.ui.elicitation", - Map.of("sessionId", sessionId, "message", message, "requestedSchema", schema), - ElicitationRpcResponse.class).thenApply(resp -> { - if ("accept".equalsIgnoreCase(resp.action()) && resp.content() != null) { + return getRpc().ui.elicitation(new SessionUiElicitationParams(sessionId, message, + new SessionUiElicitationParams.SessionUiElicitationParamsRequestedSchema("object", + Map.of("value", (Object) field), List.of("value")))) + .thenApply(resp -> { + if (resp.action() == SessionUiElicitationResult.SessionUiElicitationResultAction.ACCEPT + && resp.content() != null) { Object val = resp.content().get("value"); return val != null ? val.toString() : null; } @@ -1138,11 +1186,6 @@ public CompletableFuture input(String message, InputOptions options) { } } - @JsonIgnoreProperties(ignoreUnknown = true) - private record ElicitationRpcResponse(@JsonProperty("action") String action, - @JsonProperty("content") Map content) { - } - /** * Retrieves a registered tool by name. * @@ -1436,17 +1479,17 @@ CompletableFuture handleHooksInvoke(String hookType, JsonNode input) { * @return a future that resolves with a list of all session events * @throws IllegalStateException * if this session has been terminated - * @see AbstractSessionEvent + * @see SessionEvent */ - public CompletableFuture> getMessages() { + public CompletableFuture> getMessages() { ensureNotTerminated(); return rpc.invoke("session.getMessages", Map.of("sessionId", sessionId), GetMessagesResponse.class) .thenApply(response -> { - var events = new ArrayList(); + var events = new ArrayList(); if (response.events() != null) { for (JsonNode eventNode : response.events()) { try { - AbstractSessionEvent event = SessionEventParser.parse(eventNode); + SessionEvent event = MAPPER.treeToValue(eventNode, SessionEvent.class); if (event != null) { events.add(event); } @@ -1497,13 +1540,8 @@ public CompletableFuture abort() { */ public CompletableFuture setModel(String model, String reasoningEffort) { ensureNotTerminated(); - var params = new java.util.HashMap(); - params.put("sessionId", sessionId); - params.put("modelId", model); - if (reasoningEffort != null) { - params.put("reasoningEffort", reasoningEffort); - } - return rpc.invoke("session.model.switchTo", params, Void.class); + return getRpc().model.switchTo(new SessionModelSwitchToParams(sessionId, model, reasoningEffort, null)) + .thenApply(r -> null); } /** @@ -1561,19 +1599,15 @@ public CompletableFuture setModel(String model) { */ public CompletableFuture log(String message, String level, Boolean ephemeral, String url) { ensureNotTerminated(); - var params = new java.util.HashMap(); - params.put("sessionId", sessionId); - params.put("message", message); + SessionLogParams.SessionLogParamsLevel rpcLevel = null; if (level != null) { - params.put("level", level); - } - if (ephemeral != null) { - params.put("ephemeral", ephemeral); - } - if (url != null) { - params.put("url", url); + try { + rpcLevel = SessionLogParams.SessionLogParamsLevel.fromValue(level); + } catch (IllegalArgumentException e) { + rpcLevel = SessionLogParams.SessionLogParamsLevel.INFO; + } } - return rpc.invoke("session.log", params, Void.class); + return getRpc().log(new SessionLogParams(sessionId, message, rpcLevel, ephemeral, url)).thenApply(r -> null); } /** diff --git a/src/main/java/com/github/copilot/sdk/EventErrorHandler.java b/src/main/java/com/github/copilot/sdk/EventErrorHandler.java index 8cab08ae1..2ff77d971 100644 --- a/src/main/java/com/github/copilot/sdk/EventErrorHandler.java +++ b/src/main/java/com/github/copilot/sdk/EventErrorHandler.java @@ -4,7 +4,7 @@ package com.github.copilot.sdk; -import com.github.copilot.sdk.events.AbstractSessionEvent; +import com.github.copilot.sdk.generated.SessionEvent; /** * A handler for errors thrown by event handlers during event dispatch. @@ -54,5 +54,5 @@ public interface EventErrorHandler { * @param exception * the exception thrown by the event handler */ - void handleError(AbstractSessionEvent event, Exception exception); + void handleError(SessionEvent event, Exception exception); } diff --git a/src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java b/src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java index f1d488105..d085f7fce 100644 --- a/src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java +++ b/src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java @@ -16,8 +16,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.copilot.sdk.events.AbstractSessionEvent; -import com.github.copilot.sdk.events.SessionEventParser; +import com.github.copilot.sdk.generated.SessionEvent; import com.github.copilot.sdk.json.PermissionRequestResult; import com.github.copilot.sdk.json.PermissionRequestResultKind; import com.github.copilot.sdk.json.SessionLifecycleEvent; @@ -93,7 +92,7 @@ private void handleSessionEvent(JsonNode params) { CopilotSession session = sessions.get(sessionId); if (session != null && eventNode != null) { - AbstractSessionEvent event = SessionEventParser.parse(eventNode); + SessionEvent event = MAPPER.treeToValue(eventNode, SessionEvent.class); if (event != null) { session.dispatchEvent(event); } diff --git a/src/main/java/com/github/copilot/sdk/events/AbortEvent.java b/src/main/java/com/github/copilot/sdk/events/AbortEvent.java deleted file mode 100644 index d63185101..000000000 --- a/src/main/java/com/github/copilot/sdk/events/AbortEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: abort - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class AbortEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private AbortData data; - - @Override - public String getType() { - return "abort"; - } - - public AbortData getData() { - return data; - } - - public void setData(AbortData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record AbortData(@JsonProperty("reason") String reason) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/AbstractSessionEvent.java b/src/main/java/com/github/copilot/sdk/events/AbstractSessionEvent.java deleted file mode 100644 index 51f6d8712..000000000 --- a/src/main/java/com/github/copilot/sdk/events/AbstractSessionEvent.java +++ /dev/null @@ -1,179 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.time.OffsetDateTime; -import java.util.UUID; - -/** - * Base class for all session events in the Copilot SDK. - *

- * Session events represent all activities that occur during a Copilot - * conversation, including messages from the user and assistant, tool - * executions, and session state changes. Events are delivered to handlers - * registered via - * {@link com.github.copilot.sdk.CopilotSession#on(java.util.function.Consumer)}. - * - *

Event Categories

- *
    - *
  • Session events: {@link SessionStartEvent}, - * {@link SessionResumeEvent}, {@link SessionErrorEvent}, - * {@link SessionIdleEvent}, etc.
  • - *
  • Assistant events: {@link AssistantMessageEvent}, - * {@link AssistantMessageDeltaEvent}, {@link AssistantTurnStartEvent}, - * etc.
  • - *
  • Tool events: {@link ToolExecutionStartEvent}, - * {@link ToolExecutionCompleteEvent}, etc.
  • - *
  • User events: {@link UserMessageEvent}
  • - *
- * - *

Example Usage

- * - *
{@code
- * session.on(event -> {
- * 	if (event instanceof AssistantMessageEvent msg) {
- * 		System.out.println("Assistant: " + msg.getData().content());
- * 	} else if (event instanceof SessionIdleEvent) {
- * 		System.out.println("Session is idle");
- * 	}
- * });
- * }
- * - * @see com.github.copilot.sdk.CopilotSession#on(java.util.function.Consumer) - * @see SessionEventParser - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public abstract sealed class AbstractSessionEvent permits - // Session events - SessionStartEvent, SessionResumeEvent, SessionErrorEvent, SessionIdleEvent, SessionInfoEvent, - SessionModelChangeEvent, SessionModeChangedEvent, SessionPlanChangedEvent, SessionWorkspaceFileChangedEvent, - SessionHandoffEvent, SessionTruncationEvent, SessionSnapshotRewindEvent, SessionUsageInfoEvent, - SessionCompactionStartEvent, SessionCompactionCompleteEvent, SessionShutdownEvent, SessionContextChangedEvent, - SessionTaskCompleteEvent, - // Assistant events - AssistantTurnStartEvent, AssistantIntentEvent, AssistantReasoningEvent, AssistantReasoningDeltaEvent, - AssistantMessageEvent, AssistantMessageDeltaEvent, AssistantStreamingDeltaEvent, AssistantTurnEndEvent, - AssistantUsageEvent, AbortEvent, - // Tool events - ToolUserRequestedEvent, ToolExecutionStartEvent, ToolExecutionPartialResultEvent, ToolExecutionProgressEvent, - ToolExecutionCompleteEvent, - // Broadcast request/completion events (protocol v3) - ExternalToolRequestedEvent, ExternalToolCompletedEvent, PermissionRequestedEvent, PermissionCompletedEvent, - CommandQueuedEvent, CommandCompletedEvent, CommandExecuteEvent, ElicitationRequestedEvent, - CapabilitiesChangedEvent, ExitPlanModeRequestedEvent, ExitPlanModeCompletedEvent, SystemNotificationEvent, - // User events - UserMessageEvent, PendingMessagesModifiedEvent, - // Skill events - SkillInvokedEvent, - // Other events - SubagentStartedEvent, SubagentCompletedEvent, SubagentFailedEvent, SubagentSelectedEvent, - SubagentDeselectedEvent, HookStartEvent, HookEndEvent, SystemMessageEvent, - // Forward-compatibility placeholder for event types not yet known to this SDK - UnknownSessionEvent { - - @JsonProperty("id") - private UUID id; - - @JsonProperty("timestamp") - private OffsetDateTime timestamp; - - @JsonProperty("parentId") - private UUID parentId; - - @JsonProperty("ephemeral") - private Boolean ephemeral; - - /** - * Gets the event type discriminator string. - *

- * This corresponds to the event type in the JSON protocol (e.g., - * "assistant.message", "session.idle"). - * - * @return the event type string - */ - public abstract String getType(); - - /** - * Gets the unique identifier for this event. - * - * @return the event UUID - */ - public UUID getId() { - return id; - } - - /** - * Sets the event identifier. - * - * @param id - * the event UUID - */ - public void setId(UUID id) { - this.id = id; - } - - /** - * Gets the timestamp when this event occurred. - * - * @return the event timestamp - */ - public OffsetDateTime getTimestamp() { - return timestamp; - } - - /** - * Sets the event timestamp. - * - * @param timestamp - * the event timestamp - */ - public void setTimestamp(OffsetDateTime timestamp) { - this.timestamp = timestamp; - } - - /** - * Gets the parent event ID, if this event is a child of another. - * - * @return the parent event UUID, or {@code null} - */ - public UUID getParentId() { - return parentId; - } - - /** - * Sets the parent event ID. - * - * @param parentId - * the parent event UUID - */ - public void setParentId(UUID parentId) { - this.parentId = parentId; - } - - /** - * Returns whether this is an ephemeral event. - *

- * Ephemeral events are not persisted in session history. - * - * @return {@code true} if ephemeral, {@code false} otherwise - */ - public Boolean getEphemeral() { - return ephemeral; - } - - /** - * Sets whether this is an ephemeral event. - * - * @param ephemeral - * {@code true} if ephemeral - */ - public void setEphemeral(Boolean ephemeral) { - this.ephemeral = ephemeral; - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/AssistantIntentEvent.java b/src/main/java/com/github/copilot/sdk/events/AssistantIntentEvent.java deleted file mode 100644 index e8c693139..000000000 --- a/src/main/java/com/github/copilot/sdk/events/AssistantIntentEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: assistant.intent - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class AssistantIntentEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private AssistantIntentData data; - - @Override - public String getType() { - return "assistant.intent"; - } - - public AssistantIntentData getData() { - return data; - } - - public void setData(AssistantIntentData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record AssistantIntentData(@JsonProperty("intent") String intent) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/AssistantMessageDeltaEvent.java b/src/main/java/com/github/copilot/sdk/events/AssistantMessageDeltaEvent.java deleted file mode 100644 index f9b166186..000000000 --- a/src/main/java/com/github/copilot/sdk/events/AssistantMessageDeltaEvent.java +++ /dev/null @@ -1,39 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: assistant.message_delta - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class AssistantMessageDeltaEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private AssistantMessageDeltaData data; - - @Override - public String getType() { - return "assistant.message_delta"; - } - - public AssistantMessageDeltaData getData() { - return data; - } - - public void setData(AssistantMessageDeltaData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record AssistantMessageDeltaData(@JsonProperty("messageId") String messageId, - @JsonProperty("deltaContent") String deltaContent, - @JsonProperty("parentToolCallId") String parentToolCallId) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/AssistantMessageEvent.java b/src/main/java/com/github/copilot/sdk/events/AssistantMessageEvent.java deleted file mode 100644 index 075d3cd1b..000000000 --- a/src/main/java/com/github/copilot/sdk/events/AssistantMessageEvent.java +++ /dev/null @@ -1,95 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.Collections; -import java.util.List; - -/** - * Event representing a complete message from the assistant. - *

- * This event is fired when the assistant has finished generating a response. - * For streaming responses, use {@link AssistantMessageDeltaEvent} instead. - * - *

Example Usage

- * - *
{@code
- * session.on(event -> {
- * 	if (event instanceof AssistantMessageEvent msg) {
- * 		String content = msg.getData().content();
- * 		System.out.println("Assistant: " + content);
- * 	}
- * });
- * }
- * - * @see AssistantMessageDeltaEvent - * @see AbstractSessionEvent - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class AssistantMessageEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private AssistantMessageData data; - - /** - * {@inheritDoc} - * - * @return "assistant.message" - */ - @Override - public String getType() { - return "assistant.message"; - } - - /** - * Gets the message data. - * - * @return the message data containing content and tool requests - */ - public AssistantMessageData getData() { - return data; - } - - /** - * Sets the message data. - * - * @param data - * the message data - */ - public void setData(AssistantMessageData data) { - this.data = data; - } - - /** - * Contains the assistant message content and metadata. - */ - @JsonIgnoreProperties(ignoreUnknown = true) - public record AssistantMessageData(@JsonProperty("messageId") String messageId, - @JsonProperty("content") String content, @JsonProperty("toolRequests") List toolRequests, - @JsonProperty("parentToolCallId") String parentToolCallId, - @JsonProperty("interactionId") String interactionId, - @JsonProperty("reasoningOpaque") String reasoningOpaque, - @JsonProperty("reasoningText") String reasoningText, - @JsonProperty("encryptedContent") String encryptedContent) { - - /** Returns a defensive copy of the tool requests list. */ - @Override - public List toolRequests() { - return toolRequests == null ? null : Collections.unmodifiableList(toolRequests); - } - - /** - * Represents a request from the assistant to invoke a tool. - */ - @JsonIgnoreProperties(ignoreUnknown = true) - public record ToolRequest(@JsonProperty("toolCallId") String toolCallId, @JsonProperty("name") String name, - @JsonProperty("arguments") Object arguments) { - } - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/AssistantReasoningDeltaEvent.java b/src/main/java/com/github/copilot/sdk/events/AssistantReasoningDeltaEvent.java deleted file mode 100644 index d661f5c32..000000000 --- a/src/main/java/com/github/copilot/sdk/events/AssistantReasoningDeltaEvent.java +++ /dev/null @@ -1,38 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: assistant.reasoning_delta - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class AssistantReasoningDeltaEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private AssistantReasoningDeltaData data; - - @Override - public String getType() { - return "assistant.reasoning_delta"; - } - - public AssistantReasoningDeltaData getData() { - return data; - } - - public void setData(AssistantReasoningDeltaData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record AssistantReasoningDeltaData(@JsonProperty("reasoningId") String reasoningId, - @JsonProperty("deltaContent") String deltaContent) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/AssistantReasoningEvent.java b/src/main/java/com/github/copilot/sdk/events/AssistantReasoningEvent.java deleted file mode 100644 index 7019ed71e..000000000 --- a/src/main/java/com/github/copilot/sdk/events/AssistantReasoningEvent.java +++ /dev/null @@ -1,38 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: assistant.reasoning - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class AssistantReasoningEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private AssistantReasoningData data; - - @Override - public String getType() { - return "assistant.reasoning"; - } - - public AssistantReasoningData getData() { - return data; - } - - public void setData(AssistantReasoningData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record AssistantReasoningData(@JsonProperty("reasoningId") String reasoningId, - @JsonProperty("content") String content) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/AssistantStreamingDeltaEvent.java b/src/main/java/com/github/copilot/sdk/events/AssistantStreamingDeltaEvent.java deleted file mode 100644 index ff5c2f646..000000000 --- a/src/main/java/com/github/copilot/sdk/events/AssistantStreamingDeltaEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: assistant.streaming_delta - * - * @since 1.0.11 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class AssistantStreamingDeltaEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private AssistantStreamingDeltaData data; - - @Override - public String getType() { - return "assistant.streaming_delta"; - } - - public AssistantStreamingDeltaData getData() { - return data; - } - - public void setData(AssistantStreamingDeltaData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record AssistantStreamingDeltaData(@JsonProperty("totalResponseSizeBytes") double totalResponseSizeBytes) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/AssistantTurnEndEvent.java b/src/main/java/com/github/copilot/sdk/events/AssistantTurnEndEvent.java deleted file mode 100644 index d847ddc6a..000000000 --- a/src/main/java/com/github/copilot/sdk/events/AssistantTurnEndEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: assistant.turn_end - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class AssistantTurnEndEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private AssistantTurnEndData data; - - @Override - public String getType() { - return "assistant.turn_end"; - } - - public AssistantTurnEndData getData() { - return data; - } - - public void setData(AssistantTurnEndData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record AssistantTurnEndData(@JsonProperty("turnId") String turnId) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/AssistantTurnStartEvent.java b/src/main/java/com/github/copilot/sdk/events/AssistantTurnStartEvent.java deleted file mode 100644 index 3a1d6e5ef..000000000 --- a/src/main/java/com/github/copilot/sdk/events/AssistantTurnStartEvent.java +++ /dev/null @@ -1,38 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: assistant.turn_start - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class AssistantTurnStartEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private AssistantTurnStartData data; - - @Override - public String getType() { - return "assistant.turn_start"; - } - - public AssistantTurnStartData getData() { - return data; - } - - public void setData(AssistantTurnStartData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record AssistantTurnStartData(@JsonProperty("turnId") String turnId, - @JsonProperty("interactionId") String interactionId) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/AssistantUsageEvent.java b/src/main/java/com/github/copilot/sdk/events/AssistantUsageEvent.java deleted file mode 100644 index 9aa21925b..000000000 --- a/src/main/java/com/github/copilot/sdk/events/AssistantUsageEvent.java +++ /dev/null @@ -1,78 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * Event: assistant.usage - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class AssistantUsageEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private AssistantUsageData data; - - @Override - public String getType() { - return "assistant.usage"; - } - - public AssistantUsageData getData() { - return data; - } - - public void setData(AssistantUsageData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record AssistantUsageData(@JsonProperty("model") String model, - @JsonProperty("inputTokens") Double inputTokens, @JsonProperty("outputTokens") Double outputTokens, - @JsonProperty("cacheReadTokens") Double cacheReadTokens, - @JsonProperty("cacheWriteTokens") Double cacheWriteTokens, @JsonProperty("cost") Double cost, - @JsonProperty("duration") Double duration, @JsonProperty("initiator") String initiator, - @JsonProperty("apiCallId") String apiCallId, @JsonProperty("providerCallId") String providerCallId, - @JsonProperty("parentToolCallId") String parentToolCallId, - @JsonProperty("quotaSnapshots") Map quotaSnapshots, - @JsonProperty("copilotUsage") CopilotUsage copilotUsage) { - - /** Returns a defensive copy of the quota snapshots map. */ - @Override - public Map quotaSnapshots() { - return quotaSnapshots == null ? Collections.emptyMap() : Collections.unmodifiableMap(quotaSnapshots); - } - } - - /** - * Copilot usage details including token cost information. - */ - @JsonIgnoreProperties(ignoreUnknown = true) - public record CopilotUsage(@JsonProperty("tokenDetails") List tokenDetails, - @JsonProperty("totalNanoAiu") double totalNanoAiu) { - - /** Returns a defensive copy of the token details list. */ - @Override - public List tokenDetails() { - return tokenDetails == null ? null : Collections.unmodifiableList(tokenDetails); - } - } - - /** - * Token details for a specific token type. - */ - @JsonIgnoreProperties(ignoreUnknown = true) - public record TokenDetails(@JsonProperty("batchSize") double batchSize, - @JsonProperty("costPerBatch") double costPerBatch, @JsonProperty("tokenCount") double tokenCount, - @JsonProperty("tokenType") String tokenType) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/CapabilitiesChangedEvent.java b/src/main/java/com/github/copilot/sdk/events/CapabilitiesChangedEvent.java deleted file mode 100644 index 0db68189d..000000000 --- a/src/main/java/com/github/copilot/sdk/events/CapabilitiesChangedEvent.java +++ /dev/null @@ -1,44 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: capabilities.changed - *

- * Broadcast when the host's session capabilities change. The SDK updates - * {@link com.github.copilot.sdk.CopilotSession#getCapabilities()} accordingly. - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class CapabilitiesChangedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private CapabilitiesChangedData data; - - @Override - public String getType() { - return "capabilities.changed"; - } - - public CapabilitiesChangedData getData() { - return data; - } - - public void setData(CapabilitiesChangedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record CapabilitiesChangedData(@JsonProperty("ui") CapabilitiesChangedUi ui) { - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record CapabilitiesChangedUi(@JsonProperty("elicitation") Boolean elicitation) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/CommandCompletedEvent.java b/src/main/java/com/github/copilot/sdk/events/CommandCompletedEvent.java deleted file mode 100644 index f9aeb0f3f..000000000 --- a/src/main/java/com/github/copilot/sdk/events/CommandCompletedEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: command.completed - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class CommandCompletedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private CommandCompletedData data; - - @Override - public String getType() { - return "command.completed"; - } - - public CommandCompletedData getData() { - return data; - } - - public void setData(CommandCompletedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record CommandCompletedData(@JsonProperty("requestId") String requestId) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/CommandExecuteEvent.java b/src/main/java/com/github/copilot/sdk/events/CommandExecuteEvent.java deleted file mode 100644 index c08c4a88d..000000000 --- a/src/main/java/com/github/copilot/sdk/events/CommandExecuteEvent.java +++ /dev/null @@ -1,43 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: command.execute - *

- * Broadcast when the user executes a slash command registered by this client. - * Clients that have a matching command handler should respond via - * {@code session.commands.handlePendingCommand}. - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class CommandExecuteEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private CommandExecuteData data; - - @Override - public String getType() { - return "command.execute"; - } - - public CommandExecuteData getData() { - return data; - } - - public void setData(CommandExecuteData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record CommandExecuteData(@JsonProperty("requestId") String requestId, - @JsonProperty("command") String command, @JsonProperty("commandName") String commandName, - @JsonProperty("args") String args) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/CommandQueuedEvent.java b/src/main/java/com/github/copilot/sdk/events/CommandQueuedEvent.java deleted file mode 100644 index acd35a89c..000000000 --- a/src/main/java/com/github/copilot/sdk/events/CommandQueuedEvent.java +++ /dev/null @@ -1,38 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: command.queued - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class CommandQueuedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private CommandQueuedData data; - - @Override - public String getType() { - return "command.queued"; - } - - public CommandQueuedData getData() { - return data; - } - - public void setData(CommandQueuedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record CommandQueuedData(@JsonProperty("requestId") String requestId, - @JsonProperty("command") String command) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/ElicitationRequestedEvent.java b/src/main/java/com/github/copilot/sdk/events/ElicitationRequestedEvent.java deleted file mode 100644 index e459dfb77..000000000 --- a/src/main/java/com/github/copilot/sdk/events/ElicitationRequestedEvent.java +++ /dev/null @@ -1,54 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import java.util.List; -import java.util.Map; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: elicitation.requested - *

- * Broadcast when the server or an MCP tool requests structured input from the - * user. Clients that have an elicitation handler should respond via - * {@code session.ui.handlePendingElicitation}. - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class ElicitationRequestedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private ElicitationRequestedData data; - - @Override - public String getType() { - return "elicitation.requested"; - } - - public ElicitationRequestedData getData() { - return data; - } - - public void setData(ElicitationRequestedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record ElicitationRequestedData(@JsonProperty("requestId") String requestId, - @JsonProperty("toolCallId") String toolCallId, @JsonProperty("elicitationSource") String elicitationSource, - @JsonProperty("message") String message, @JsonProperty("mode") String mode, - @JsonProperty("requestedSchema") ElicitationRequestedSchema requestedSchema, - @JsonProperty("url") String url) { - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record ElicitationRequestedSchema(@JsonProperty("type") String type, - @JsonProperty("properties") Map properties, - @JsonProperty("required") List required) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/ExitPlanModeCompletedEvent.java b/src/main/java/com/github/copilot/sdk/events/ExitPlanModeCompletedEvent.java deleted file mode 100644 index 217859e43..000000000 --- a/src/main/java/com/github/copilot/sdk/events/ExitPlanModeCompletedEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: exit_plan_mode.completed - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class ExitPlanModeCompletedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private ExitPlanModeCompletedData data; - - @Override - public String getType() { - return "exit_plan_mode.completed"; - } - - public ExitPlanModeCompletedData getData() { - return data; - } - - public void setData(ExitPlanModeCompletedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record ExitPlanModeCompletedData(@JsonProperty("requestId") String requestId) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/ExitPlanModeRequestedEvent.java b/src/main/java/com/github/copilot/sdk/events/ExitPlanModeRequestedEvent.java deleted file mode 100644 index b0019c3ce..000000000 --- a/src/main/java/com/github/copilot/sdk/events/ExitPlanModeRequestedEvent.java +++ /dev/null @@ -1,39 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: exit_plan_mode.requested - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class ExitPlanModeRequestedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private ExitPlanModeRequestedData data; - - @Override - public String getType() { - return "exit_plan_mode.requested"; - } - - public ExitPlanModeRequestedData getData() { - return data; - } - - public void setData(ExitPlanModeRequestedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record ExitPlanModeRequestedData(@JsonProperty("requestId") String requestId, - @JsonProperty("summary") String summary, @JsonProperty("planContent") String planContent, - @JsonProperty("actions") String[] actions, @JsonProperty("recommendedAction") String recommendedAction) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/ExternalToolCompletedEvent.java b/src/main/java/com/github/copilot/sdk/events/ExternalToolCompletedEvent.java deleted file mode 100644 index 83a582720..000000000 --- a/src/main/java/com/github/copilot/sdk/events/ExternalToolCompletedEvent.java +++ /dev/null @@ -1,40 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: external_tool.completed - *

- * Broadcast when a pending tool call has been resolved by a client (protocol - * v3). - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class ExternalToolCompletedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private ExternalToolCompletedData data; - - @Override - public String getType() { - return "external_tool.completed"; - } - - public ExternalToolCompletedData getData() { - return data; - } - - public void setData(ExternalToolCompletedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record ExternalToolCompletedData(@JsonProperty("requestId") String requestId) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/ExternalToolRequestedEvent.java b/src/main/java/com/github/copilot/sdk/events/ExternalToolRequestedEvent.java deleted file mode 100644 index 8eb11f5b8..000000000 --- a/src/main/java/com/github/copilot/sdk/events/ExternalToolRequestedEvent.java +++ /dev/null @@ -1,43 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: external_tool.requested - *

- * Broadcast when the CLI needs a client to handle a tool call (protocol v3). - * Clients that own the named tool should respond via - * {@code session.tools.handlePendingToolCall}. - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class ExternalToolRequestedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private ExternalToolRequestedData data; - - @Override - public String getType() { - return "external_tool.requested"; - } - - public ExternalToolRequestedData getData() { - return data; - } - - public void setData(ExternalToolRequestedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record ExternalToolRequestedData(@JsonProperty("requestId") String requestId, - @JsonProperty("sessionId") String sessionId, @JsonProperty("toolCallId") String toolCallId, - @JsonProperty("toolName") String toolName, @JsonProperty("arguments") Object arguments) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/HookEndEvent.java b/src/main/java/com/github/copilot/sdk/events/HookEndEvent.java deleted file mode 100644 index 9ace18171..000000000 --- a/src/main/java/com/github/copilot/sdk/events/HookEndEvent.java +++ /dev/null @@ -1,43 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: hook.end - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class HookEndEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private HookEndData data; - - @Override - public String getType() { - return "hook.end"; - } - - public HookEndData getData() { - return data; - } - - public void setData(HookEndData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record HookEndData(@JsonProperty("hookInvocationId") String hookInvocationId, - @JsonProperty("hookType") String hookType, @JsonProperty("output") Object output, - @JsonProperty("success") boolean success, @JsonProperty("error") HookError error) { - - @JsonIgnoreProperties(ignoreUnknown = true) - public record HookError(@JsonProperty("message") String message, @JsonProperty("stack") String stack) { - } - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/HookStartEvent.java b/src/main/java/com/github/copilot/sdk/events/HookStartEvent.java deleted file mode 100644 index 9c1f5c0ea..000000000 --- a/src/main/java/com/github/copilot/sdk/events/HookStartEvent.java +++ /dev/null @@ -1,38 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: hook.start - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class HookStartEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private HookStartData data; - - @Override - public String getType() { - return "hook.start"; - } - - public HookStartData getData() { - return data; - } - - public void setData(HookStartData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record HookStartData(@JsonProperty("hookInvocationId") String hookInvocationId, - @JsonProperty("hookType") String hookType, @JsonProperty("input") Object input) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/PendingMessagesModifiedEvent.java b/src/main/java/com/github/copilot/sdk/events/PendingMessagesModifiedEvent.java deleted file mode 100644 index 6eb863c78..000000000 --- a/src/main/java/com/github/copilot/sdk/events/PendingMessagesModifiedEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: pending_messages.modified - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class PendingMessagesModifiedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private PendingMessagesModifiedData data; - - @Override - public String getType() { - return "pending_messages.modified"; - } - - public PendingMessagesModifiedData getData() { - return data; - } - - public void setData(PendingMessagesModifiedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record PendingMessagesModifiedData() { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/PermissionCompletedEvent.java b/src/main/java/com/github/copilot/sdk/events/PermissionCompletedEvent.java deleted file mode 100644 index 90daf3b49..000000000 --- a/src/main/java/com/github/copilot/sdk/events/PermissionCompletedEvent.java +++ /dev/null @@ -1,45 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: permission.completed - *

- * Broadcast when a pending permission request has been resolved by a client - * (protocol v3). - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class PermissionCompletedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private PermissionCompletedData data; - - @Override - public String getType() { - return "permission.completed"; - } - - public PermissionCompletedData getData() { - return data; - } - - public void setData(PermissionCompletedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record PermissionCompletedData(@JsonProperty("requestId") String requestId, - @JsonProperty("result") PermissionCompletedResult result) { - - @JsonIgnoreProperties(ignoreUnknown = true) - public record PermissionCompletedResult(@JsonProperty("kind") String kind) { - } - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/PermissionRequestedEvent.java b/src/main/java/com/github/copilot/sdk/events/PermissionRequestedEvent.java deleted file mode 100644 index 7ebce5ac7..000000000 --- a/src/main/java/com/github/copilot/sdk/events/PermissionRequestedEvent.java +++ /dev/null @@ -1,44 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.github.copilot.sdk.json.PermissionRequest; - -/** - * Event: permission.requested - *

- * Broadcast when the CLI needs a client to handle a permission request - * (protocol v3). Clients that have a permission handler should respond via - * {@code session.permissions.handlePendingPermissionRequest}. - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class PermissionRequestedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private PermissionRequestedData data; - - @Override - public String getType() { - return "permission.requested"; - } - - public PermissionRequestedData getData() { - return data; - } - - public void setData(PermissionRequestedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record PermissionRequestedData(@JsonProperty("requestId") String requestId, - @JsonProperty("permissionRequest") PermissionRequest permissionRequest, - @JsonProperty("resolvedByHook") Boolean resolvedByHook) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SessionCompactionCompleteEvent.java b/src/main/java/com/github/copilot/sdk/events/SessionCompactionCompleteEvent.java deleted file mode 100644 index 57036e9d8..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SessionCompactionCompleteEvent.java +++ /dev/null @@ -1,54 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: session.compaction_complete - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SessionCompactionCompleteEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SessionCompactionCompleteData data; - - @Override - public String getType() { - return "session.compaction_complete"; - } - - public SessionCompactionCompleteData getData() { - return data; - } - - public void setData(SessionCompactionCompleteData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SessionCompactionCompleteData(@JsonProperty("success") boolean success, - @JsonProperty("error") String error, @JsonProperty("preCompactionTokens") Double preCompactionTokens, - @JsonProperty("postCompactionTokens") Double postCompactionTokens, - @JsonProperty("preCompactionMessagesLength") Double preCompactionMessagesLength, - @JsonProperty("messagesRemoved") Double messagesRemoved, - @JsonProperty("tokensRemoved") Double tokensRemoved, @JsonProperty("summaryContent") String summaryContent, - @JsonProperty("checkpointNumber") Double checkpointNumber, - @JsonProperty("checkpointPath") String checkpointPath, - @JsonProperty("compactionTokensUsed") CompactionTokensUsed compactionTokensUsed, - @JsonProperty("requestId") String requestId) { - } - - /** - * Token usage information for the compaction operation. - */ - @JsonIgnoreProperties(ignoreUnknown = true) - public record CompactionTokensUsed(@JsonProperty("input") double input, @JsonProperty("output") double output, - @JsonProperty("cachedInput") double cachedInput) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SessionCompactionStartEvent.java b/src/main/java/com/github/copilot/sdk/events/SessionCompactionStartEvent.java deleted file mode 100644 index ad29b37f8..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SessionCompactionStartEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: session.compaction_start - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SessionCompactionStartEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SessionCompactionStartData data; - - @Override - public String getType() { - return "session.compaction_start"; - } - - public SessionCompactionStartData getData() { - return data; - } - - public void setData(SessionCompactionStartData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SessionCompactionStartData() { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SessionContextChangedEvent.java b/src/main/java/com/github/copilot/sdk/events/SessionContextChangedEvent.java deleted file mode 100644 index 52e41f154..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SessionContextChangedEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.github.copilot.sdk.json.SessionContext; - -/** - * Event: session.context_changed - *

- * Fired when the working directory context changes between turns. Contains the - * updated context information including cwd, git root, repository, and branch. - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SessionContextChangedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SessionContext data; - - @Override - public String getType() { - return "session.context_changed"; - } - - public SessionContext getData() { - return data; - } - - public void setData(SessionContext data) { - this.data = data; - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SessionErrorEvent.java b/src/main/java/com/github/copilot/sdk/events/SessionErrorEvent.java deleted file mode 100644 index ffa9e6d9e..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SessionErrorEvent.java +++ /dev/null @@ -1,39 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: session.error - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SessionErrorEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SessionErrorData data; - - @Override - public String getType() { - return "session.error"; - } - - public SessionErrorData getData() { - return data; - } - - public void setData(SessionErrorData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SessionErrorData(@JsonProperty("errorType") String errorType, @JsonProperty("message") String message, - @JsonProperty("stack") String stack, @JsonProperty("statusCode") Double statusCode, - @JsonProperty("providerCallId") String providerCallId) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SessionEventParser.java b/src/main/java/com/github/copilot/sdk/events/SessionEventParser.java deleted file mode 100644 index dda971769..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SessionEventParser.java +++ /dev/null @@ -1,144 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import java.util.HashMap; -import java.util.Map; - -/** - * Parser for session events that handles polymorphic deserialization. - *

- * This class deserializes JSON event data into the appropriate - * {@link AbstractSessionEvent} subclass based on the "type" field. It is used - * internally by the SDK to convert server events to Java objects. - * - *

Supported Event Types

- *
    - *
  • Session: session.start, session.resume, session.error, - * session.idle, session.info, etc.
  • - *
  • Assistant: assistant.message, assistant.message_delta, - * assistant.turn_start, assistant.turn_end, etc.
  • - *
  • Tool: tool.execution_start, tool.execution_complete, - * etc.
  • - *
  • User: user.message, pending_messages.modified
  • - *
  • Subagent: subagent.started, subagent.completed, - * etc.
  • - *
- * - * @see AbstractSessionEvent - * @since 1.0.0 - */ -public class SessionEventParser { - - private static final Logger LOG = Logger.getLogger(SessionEventParser.class.getName()); - private static final ObjectMapper MAPPER; - private static final Map> TYPE_MAP = new HashMap<>(); - - static { - MAPPER = new ObjectMapper(); - MAPPER.registerModule(new JavaTimeModule()); - MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - - TYPE_MAP.put("session.start", SessionStartEvent.class); - TYPE_MAP.put("session.resume", SessionResumeEvent.class); - TYPE_MAP.put("session.error", SessionErrorEvent.class); - TYPE_MAP.put("session.idle", SessionIdleEvent.class); - TYPE_MAP.put("session.info", SessionInfoEvent.class); - TYPE_MAP.put("session.model_change", SessionModelChangeEvent.class); - TYPE_MAP.put("session.mode_changed", SessionModeChangedEvent.class); - TYPE_MAP.put("session.plan_changed", SessionPlanChangedEvent.class); - TYPE_MAP.put("session.workspace_file_changed", SessionWorkspaceFileChangedEvent.class); - TYPE_MAP.put("session.handoff", SessionHandoffEvent.class); - TYPE_MAP.put("session.truncation", SessionTruncationEvent.class); - TYPE_MAP.put("session.snapshot_rewind", SessionSnapshotRewindEvent.class); - TYPE_MAP.put("session.usage_info", SessionUsageInfoEvent.class); - TYPE_MAP.put("session.compaction_start", SessionCompactionStartEvent.class); - TYPE_MAP.put("session.compaction_complete", SessionCompactionCompleteEvent.class); - TYPE_MAP.put("session.context_changed", SessionContextChangedEvent.class); - TYPE_MAP.put("session.task_complete", SessionTaskCompleteEvent.class); - TYPE_MAP.put("user.message", UserMessageEvent.class); - TYPE_MAP.put("pending_messages.modified", PendingMessagesModifiedEvent.class); - TYPE_MAP.put("assistant.turn_start", AssistantTurnStartEvent.class); - TYPE_MAP.put("assistant.intent", AssistantIntentEvent.class); - TYPE_MAP.put("assistant.reasoning", AssistantReasoningEvent.class); - TYPE_MAP.put("assistant.reasoning_delta", AssistantReasoningDeltaEvent.class); - TYPE_MAP.put("assistant.message", AssistantMessageEvent.class); - TYPE_MAP.put("assistant.message_delta", AssistantMessageDeltaEvent.class); - TYPE_MAP.put("assistant.streaming_delta", AssistantStreamingDeltaEvent.class); - TYPE_MAP.put("assistant.turn_end", AssistantTurnEndEvent.class); - TYPE_MAP.put("assistant.usage", AssistantUsageEvent.class); - TYPE_MAP.put("abort", AbortEvent.class); - TYPE_MAP.put("tool.user_requested", ToolUserRequestedEvent.class); - TYPE_MAP.put("tool.execution_start", ToolExecutionStartEvent.class); - TYPE_MAP.put("tool.execution_partial_result", ToolExecutionPartialResultEvent.class); - TYPE_MAP.put("tool.execution_progress", ToolExecutionProgressEvent.class); - TYPE_MAP.put("tool.execution_complete", ToolExecutionCompleteEvent.class); - TYPE_MAP.put("subagent.started", SubagentStartedEvent.class); - TYPE_MAP.put("subagent.completed", SubagentCompletedEvent.class); - TYPE_MAP.put("subagent.failed", SubagentFailedEvent.class); - TYPE_MAP.put("subagent.selected", SubagentSelectedEvent.class); - TYPE_MAP.put("subagent.deselected", SubagentDeselectedEvent.class); - TYPE_MAP.put("hook.start", HookStartEvent.class); - TYPE_MAP.put("hook.end", HookEndEvent.class); - TYPE_MAP.put("system.message", SystemMessageEvent.class); - TYPE_MAP.put("session.shutdown", SessionShutdownEvent.class); - TYPE_MAP.put("skill.invoked", SkillInvokedEvent.class); - TYPE_MAP.put("external_tool.requested", ExternalToolRequestedEvent.class); - TYPE_MAP.put("external_tool.completed", ExternalToolCompletedEvent.class); - TYPE_MAP.put("permission.requested", PermissionRequestedEvent.class); - TYPE_MAP.put("permission.completed", PermissionCompletedEvent.class); - TYPE_MAP.put("command.queued", CommandQueuedEvent.class); - TYPE_MAP.put("command.completed", CommandCompletedEvent.class); - TYPE_MAP.put("command.execute", CommandExecuteEvent.class); - TYPE_MAP.put("elicitation.requested", ElicitationRequestedEvent.class); - TYPE_MAP.put("capabilities.changed", CapabilitiesChangedEvent.class); - TYPE_MAP.put("exit_plan_mode.requested", ExitPlanModeRequestedEvent.class); - TYPE_MAP.put("exit_plan_mode.completed", ExitPlanModeCompletedEvent.class); - TYPE_MAP.put("system.notification", SystemNotificationEvent.class); - } - - /** - * Parses a JsonNode into the appropriate SessionEvent subclass. - * - * @param node - * the JSON node representing an event - * @return the parsed event, or {@code null} if parsing fails or type is unknown - */ - public static AbstractSessionEvent parse(JsonNode node) { - try { - String type = node.has("type") ? node.get("type").asText() : null; - - if (type == null) { - LOG.warning("Missing 'type' field in event"); - return null; - } - - Class eventClass = TYPE_MAP.get(type); - if (eventClass == null) { - LOG.fine("Unknown event type: " + type + " — returning UnknownSessionEvent for forward compatibility"); - UnknownSessionEvent base = MAPPER.treeToValue(node, UnknownSessionEvent.class); - UnknownSessionEvent result = new UnknownSessionEvent(type); - result.setId(base.getId()); - result.setTimestamp(base.getTimestamp()); - result.setParentId(base.getParentId()); - result.setEphemeral(base.getEphemeral()); - return result; - } - - return MAPPER.treeToValue(node, eventClass); - } catch (Exception e) { - LOG.log(Level.SEVERE, "Failed to parse session event", e); - return null; - } - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SessionHandoffEvent.java b/src/main/java/com/github/copilot/sdk/events/SessionHandoffEvent.java deleted file mode 100644 index 08e8f8c42..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SessionHandoffEvent.java +++ /dev/null @@ -1,47 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.time.OffsetDateTime; - -/** - * Event: session.handoff - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SessionHandoffEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SessionHandoffData data; - - @Override - public String getType() { - return "session.handoff"; - } - - public SessionHandoffData getData() { - return data; - } - - public void setData(SessionHandoffData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SessionHandoffData(@JsonProperty("handoffTime") OffsetDateTime handoffTime, - @JsonProperty("sourceType") String sourceType, @JsonProperty("repository") Repository repository, - @JsonProperty("context") String context, @JsonProperty("summary") String summary, - @JsonProperty("remoteSessionId") String remoteSessionId) { - - @JsonIgnoreProperties(ignoreUnknown = true) - public record Repository(@JsonProperty("owner") String owner, @JsonProperty("name") String name, - @JsonProperty("branch") String branch) { - } - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SessionIdleEvent.java b/src/main/java/com/github/copilot/sdk/events/SessionIdleEvent.java deleted file mode 100644 index bb77b6ed0..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SessionIdleEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: session.idle - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SessionIdleEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SessionIdleData data; - - @Override - public String getType() { - return "session.idle"; - } - - public SessionIdleData getData() { - return data; - } - - public void setData(SessionIdleData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SessionIdleData() { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SessionInfoEvent.java b/src/main/java/com/github/copilot/sdk/events/SessionInfoEvent.java deleted file mode 100644 index dd1fe7ccb..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SessionInfoEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: session.info - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SessionInfoEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SessionInfoData data; - - @Override - public String getType() { - return "session.info"; - } - - public SessionInfoData getData() { - return data; - } - - public void setData(SessionInfoData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SessionInfoData(@JsonProperty("infoType") String infoType, @JsonProperty("message") String message) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SessionModeChangedEvent.java b/src/main/java/com/github/copilot/sdk/events/SessionModeChangedEvent.java deleted file mode 100644 index 3c5b5d661..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SessionModeChangedEvent.java +++ /dev/null @@ -1,38 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: session.mode_changed - * - * @since 1.0.10 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SessionModeChangedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SessionModeChangedData data; - - @Override - public String getType() { - return "session.mode_changed"; - } - - public SessionModeChangedData getData() { - return data; - } - - public void setData(SessionModeChangedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SessionModeChangedData(@JsonProperty("previousMode") String previousMode, - @JsonProperty("newMode") String newMode) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SessionModelChangeEvent.java b/src/main/java/com/github/copilot/sdk/events/SessionModelChangeEvent.java deleted file mode 100644 index 57d0b5499..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SessionModelChangeEvent.java +++ /dev/null @@ -1,38 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: session.model_change - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SessionModelChangeEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SessionModelChangeData data; - - @Override - public String getType() { - return "session.model_change"; - } - - public SessionModelChangeData getData() { - return data; - } - - public void setData(SessionModelChangeData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SessionModelChangeData(@JsonProperty("previousModel") String previousModel, - @JsonProperty("newModel") String newModel) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SessionPlanChangedEvent.java b/src/main/java/com/github/copilot/sdk/events/SessionPlanChangedEvent.java deleted file mode 100644 index 2010cf146..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SessionPlanChangedEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: session.plan_changed - * - * @since 1.0.10 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SessionPlanChangedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SessionPlanChangedData data; - - @Override - public String getType() { - return "session.plan_changed"; - } - - public SessionPlanChangedData getData() { - return data; - } - - public void setData(SessionPlanChangedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SessionPlanChangedData(@JsonProperty("operation") String operation) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SessionResumeEvent.java b/src/main/java/com/github/copilot/sdk/events/SessionResumeEvent.java deleted file mode 100644 index bf305bc30..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SessionResumeEvent.java +++ /dev/null @@ -1,40 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.time.OffsetDateTime; - -/** - * Event: session.resume - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SessionResumeEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SessionResumeData data; - - @Override - public String getType() { - return "session.resume"; - } - - public SessionResumeData getData() { - return data; - } - - public void setData(SessionResumeData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SessionResumeData(@JsonProperty("resumeTime") OffsetDateTime resumeTime, - @JsonProperty("eventCount") double eventCount) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SessionShutdownEvent.java b/src/main/java/com/github/copilot/sdk/events/SessionShutdownEvent.java deleted file mode 100644 index 9a128500a..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SessionShutdownEvent.java +++ /dev/null @@ -1,71 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.List; -import java.util.Map; - -/** - * Event: session.shutdown - *

- * This event is emitted when a session is shutting down, either routinely or - * due to an error. It contains metrics about the session's usage. - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SessionShutdownEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SessionShutdownData data; - - @Override - public String getType() { - return "session.shutdown"; - } - - public SessionShutdownData getData() { - return data; - } - - public void setData(SessionShutdownData data) { - this.data = data; - } - - /** - * Data for the session shutdown event. - */ - @JsonIgnoreProperties(ignoreUnknown = true) - public record SessionShutdownData(@JsonProperty("shutdownType") ShutdownType shutdownType, - @JsonProperty("errorReason") String errorReason, - @JsonProperty("totalPremiumRequests") double totalPremiumRequests, - @JsonProperty("totalApiDurationMs") double totalApiDurationMs, - @JsonProperty("sessionStartTime") double sessionStartTime, - @JsonProperty("codeChanges") CodeChanges codeChanges, - @JsonProperty("modelMetrics") Map modelMetrics, - @JsonProperty("currentModel") String currentModel) { - } - - /** - * Code changes made during the session. - */ - @JsonIgnoreProperties(ignoreUnknown = true) - public record CodeChanges(@JsonProperty("linesAdded") double linesAdded, - @JsonProperty("linesRemoved") double linesRemoved, - @JsonProperty("filesModified") List filesModified) { - } - - /** - * Type of session shutdown. - */ - public enum ShutdownType { - @JsonProperty("routine") - ROUTINE, @JsonProperty("error") - ERROR - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SessionSnapshotRewindEvent.java b/src/main/java/com/github/copilot/sdk/events/SessionSnapshotRewindEvent.java deleted file mode 100644 index ae7b0f3c5..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SessionSnapshotRewindEvent.java +++ /dev/null @@ -1,40 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: session.snapshot_rewind - *

- * Indicates that the session has been rewound to a previous snapshot. - * - * @since 1.0.4 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SessionSnapshotRewindEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SessionSnapshotRewindData data; - - @Override - public String getType() { - return "session.snapshot_rewind"; - } - - public SessionSnapshotRewindData getData() { - return data; - } - - public void setData(SessionSnapshotRewindData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SessionSnapshotRewindData(@JsonProperty("upToEventId") String upToEventId, - @JsonProperty("eventsRemoved") int eventsRemoved) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SessionStartEvent.java b/src/main/java/com/github/copilot/sdk/events/SessionStartEvent.java deleted file mode 100644 index 317b4a470..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SessionStartEvent.java +++ /dev/null @@ -1,41 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.time.OffsetDateTime; - -/** - * Event: session.start - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SessionStartEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SessionStartData data; - - @Override - public String getType() { - return "session.start"; - } - - public SessionStartData getData() { - return data; - } - - public void setData(SessionStartData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SessionStartData(@JsonProperty("sessionId") String sessionId, @JsonProperty("version") double version, - @JsonProperty("producer") String producer, @JsonProperty("copilotVersion") String copilotVersion, - @JsonProperty("startTime") OffsetDateTime startTime, @JsonProperty("selectedModel") String selectedModel) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SessionTaskCompleteEvent.java b/src/main/java/com/github/copilot/sdk/events/SessionTaskCompleteEvent.java deleted file mode 100644 index d82b516ab..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SessionTaskCompleteEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: session.task_complete - * - * @since 1.0.11 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SessionTaskCompleteEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SessionTaskCompleteData data; - - @Override - public String getType() { - return "session.task_complete"; - } - - public SessionTaskCompleteData getData() { - return data; - } - - public void setData(SessionTaskCompleteData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SessionTaskCompleteData(@JsonProperty("summary") String summary) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SessionTruncationEvent.java b/src/main/java/com/github/copilot/sdk/events/SessionTruncationEvent.java deleted file mode 100644 index 04971cb97..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SessionTruncationEvent.java +++ /dev/null @@ -1,44 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: session.truncation - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SessionTruncationEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SessionTruncationData data; - - @Override - public String getType() { - return "session.truncation"; - } - - public SessionTruncationData getData() { - return data; - } - - public void setData(SessionTruncationData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SessionTruncationData(@JsonProperty("tokenLimit") double tokenLimit, - @JsonProperty("preTruncationTokensInMessages") double preTruncationTokensInMessages, - @JsonProperty("preTruncationMessagesLength") double preTruncationMessagesLength, - @JsonProperty("postTruncationTokensInMessages") double postTruncationTokensInMessages, - @JsonProperty("postTruncationMessagesLength") double postTruncationMessagesLength, - @JsonProperty("tokensRemovedDuringTruncation") double tokensRemovedDuringTruncation, - @JsonProperty("messagesRemovedDuringTruncation") double messagesRemovedDuringTruncation, - @JsonProperty("performedBy") String performedBy) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SessionUsageInfoEvent.java b/src/main/java/com/github/copilot/sdk/events/SessionUsageInfoEvent.java deleted file mode 100644 index 1bf10d7de..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SessionUsageInfoEvent.java +++ /dev/null @@ -1,39 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: session.usage_info - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SessionUsageInfoEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SessionUsageInfoData data; - - @Override - public String getType() { - return "session.usage_info"; - } - - public SessionUsageInfoData getData() { - return data; - } - - public void setData(SessionUsageInfoData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SessionUsageInfoData(@JsonProperty("tokenLimit") double tokenLimit, - @JsonProperty("currentTokens") double currentTokens, - @JsonProperty("messagesLength") double messagesLength) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SessionWorkspaceFileChangedEvent.java b/src/main/java/com/github/copilot/sdk/events/SessionWorkspaceFileChangedEvent.java deleted file mode 100644 index 0ed30aeb8..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SessionWorkspaceFileChangedEvent.java +++ /dev/null @@ -1,38 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: session.workspace_file_changed - * - * @since 1.0.10 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SessionWorkspaceFileChangedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SessionWorkspaceFileChangedData data; - - @Override - public String getType() { - return "session.workspace_file_changed"; - } - - public SessionWorkspaceFileChangedData getData() { - return data; - } - - public void setData(SessionWorkspaceFileChangedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SessionWorkspaceFileChangedData(@JsonProperty("path") String path, - @JsonProperty("operation") String operation) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SkillInvokedEvent.java b/src/main/java/com/github/copilot/sdk/events/SkillInvokedEvent.java deleted file mode 100644 index 4ed8e2327..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SkillInvokedEvent.java +++ /dev/null @@ -1,46 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.List; - -/** - * Event: skill.invoked - *

- * This event is emitted when a skill is invoked during a session. - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SkillInvokedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SkillInvokedData data; - - @Override - public String getType() { - return "skill.invoked"; - } - - public SkillInvokedData getData() { - return data; - } - - public void setData(SkillInvokedData data) { - this.data = data; - } - - /** - * Data for the skill invoked event. - */ - @JsonIgnoreProperties(ignoreUnknown = true) - public record SkillInvokedData(@JsonProperty("name") String name, @JsonProperty("path") String path, - @JsonProperty("content") String content, @JsonProperty("allowedTools") List allowedTools, - @JsonProperty("pluginName") String pluginName, @JsonProperty("pluginVersion") String pluginVersion) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SubagentCompletedEvent.java b/src/main/java/com/github/copilot/sdk/events/SubagentCompletedEvent.java deleted file mode 100644 index 31bb9cc70..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SubagentCompletedEvent.java +++ /dev/null @@ -1,38 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: subagent.completed - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SubagentCompletedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SubagentCompletedData data; - - @Override - public String getType() { - return "subagent.completed"; - } - - public SubagentCompletedData getData() { - return data; - } - - public void setData(SubagentCompletedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SubagentCompletedData(@JsonProperty("toolCallId") String toolCallId, - @JsonProperty("agentName") String agentName) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SubagentDeselectedEvent.java b/src/main/java/com/github/copilot/sdk/events/SubagentDeselectedEvent.java deleted file mode 100644 index f49f46330..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SubagentDeselectedEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: subagent.deselected - * - * @since 1.0.11 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SubagentDeselectedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SubagentDeselectedData data; - - @Override - public String getType() { - return "subagent.deselected"; - } - - public SubagentDeselectedData getData() { - return data; - } - - public void setData(SubagentDeselectedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SubagentDeselectedData() { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SubagentFailedEvent.java b/src/main/java/com/github/copilot/sdk/events/SubagentFailedEvent.java deleted file mode 100644 index d1b9426bd..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SubagentFailedEvent.java +++ /dev/null @@ -1,38 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: subagent.failed - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SubagentFailedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SubagentFailedData data; - - @Override - public String getType() { - return "subagent.failed"; - } - - public SubagentFailedData getData() { - return data; - } - - public void setData(SubagentFailedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SubagentFailedData(@JsonProperty("toolCallId") String toolCallId, - @JsonProperty("agentName") String agentName, @JsonProperty("error") String error) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SubagentSelectedEvent.java b/src/main/java/com/github/copilot/sdk/events/SubagentSelectedEvent.java deleted file mode 100644 index 6f8737110..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SubagentSelectedEvent.java +++ /dev/null @@ -1,44 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: subagent.selected - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SubagentSelectedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SubagentSelectedData data; - - @Override - public String getType() { - return "subagent.selected"; - } - - public SubagentSelectedData getData() { - return data; - } - - public void setData(SubagentSelectedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SubagentSelectedData(@JsonProperty("agentName") String agentName, - @JsonProperty("agentDisplayName") String agentDisplayName, @JsonProperty("tools") String[] tools) { - - /** Returns a defensive copy of the tools array. */ - @Override - public String[] tools() { - return tools == null ? null : tools.clone(); - } - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SubagentStartedEvent.java b/src/main/java/com/github/copilot/sdk/events/SubagentStartedEvent.java deleted file mode 100644 index 440ffc43e..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SubagentStartedEvent.java +++ /dev/null @@ -1,39 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: subagent.started - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SubagentStartedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SubagentStartedData data; - - @Override - public String getType() { - return "subagent.started"; - } - - public SubagentStartedData getData() { - return data; - } - - public void setData(SubagentStartedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SubagentStartedData(@JsonProperty("toolCallId") String toolCallId, - @JsonProperty("agentName") String agentName, @JsonProperty("agentDisplayName") String agentDisplayName, - @JsonProperty("agentDescription") String agentDescription) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SystemMessageEvent.java b/src/main/java/com/github/copilot/sdk/events/SystemMessageEvent.java deleted file mode 100644 index e895b3ef1..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SystemMessageEvent.java +++ /dev/null @@ -1,40 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.Map; - -/** - * Event: system.message - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SystemMessageEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SystemMessageData data; - - @Override - public String getType() { - return "system.message"; - } - - public SystemMessageData getData() { - return data; - } - - public void setData(SystemMessageData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SystemMessageData(@JsonProperty("content") String content, @JsonProperty("type") String type, - @JsonProperty("metadata") Map metadata) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/SystemNotificationEvent.java b/src/main/java/com/github/copilot/sdk/events/SystemNotificationEvent.java deleted file mode 100644 index 38711f276..000000000 --- a/src/main/java/com/github/copilot/sdk/events/SystemNotificationEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: system.notification - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class SystemNotificationEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private SystemNotificationData data; - - @Override - public String getType() { - return "system.notification"; - } - - public SystemNotificationData getData() { - return data; - } - - public void setData(SystemNotificationData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record SystemNotificationData(@JsonProperty("content") String content, @JsonProperty("kind") Object kind) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/ToolExecutionCompleteEvent.java b/src/main/java/com/github/copilot/sdk/events/ToolExecutionCompleteEvent.java deleted file mode 100644 index f085f43ce..000000000 --- a/src/main/java/com/github/copilot/sdk/events/ToolExecutionCompleteEvent.java +++ /dev/null @@ -1,60 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.Collections; -import java.util.Map; - -/** - * Event: tool.execution_complete - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class ToolExecutionCompleteEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private ToolExecutionCompleteData data; - - @Override - public String getType() { - return "tool.execution_complete"; - } - - public ToolExecutionCompleteData getData() { - return data; - } - - public void setData(ToolExecutionCompleteData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record ToolExecutionCompleteData(@JsonProperty("toolCallId") String toolCallId, - @JsonProperty("success") boolean success, @JsonProperty("model") String model, - @JsonProperty("interactionId") String interactionId, - @JsonProperty("isUserRequested") Boolean isUserRequested, @JsonProperty("result") Result result, - @JsonProperty("error") Error error, @JsonProperty("toolTelemetry") Map toolTelemetry, - @JsonProperty("parentToolCallId") String parentToolCallId) { - - /** Returns a defensive copy of the tool telemetry map. */ - @Override - public Map toolTelemetry() { - return toolTelemetry == null ? null : Collections.unmodifiableMap(toolTelemetry); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record Result(@JsonProperty("content") String content, - @JsonProperty("detailedContent") String detailedContent) { - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record Error(@JsonProperty("message") String message, @JsonProperty("code") String code) { - } - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/ToolExecutionPartialResultEvent.java b/src/main/java/com/github/copilot/sdk/events/ToolExecutionPartialResultEvent.java deleted file mode 100644 index 0fcf7f75b..000000000 --- a/src/main/java/com/github/copilot/sdk/events/ToolExecutionPartialResultEvent.java +++ /dev/null @@ -1,38 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: tool.execution_partial_result - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class ToolExecutionPartialResultEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private ToolExecutionPartialResultData data; - - @Override - public String getType() { - return "tool.execution_partial_result"; - } - - public ToolExecutionPartialResultData getData() { - return data; - } - - public void setData(ToolExecutionPartialResultData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record ToolExecutionPartialResultData(@JsonProperty("toolCallId") String toolCallId, - @JsonProperty("partialOutput") String partialOutput) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/ToolExecutionProgressEvent.java b/src/main/java/com/github/copilot/sdk/events/ToolExecutionProgressEvent.java deleted file mode 100644 index 380073123..000000000 --- a/src/main/java/com/github/copilot/sdk/events/ToolExecutionProgressEvent.java +++ /dev/null @@ -1,42 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event fired when a tool execution reports progress. - *

- * This event provides progress updates during tool execution. - * - * @since 1.0.1 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class ToolExecutionProgressEvent extends AbstractSessionEvent { - - public static final String TYPE = "tool.execution_progress"; - - @JsonProperty("data") - private ToolExecutionProgressData data; - - @Override - public String getType() { - return TYPE; - } - - public ToolExecutionProgressData getData() { - return data; - } - - public void setData(ToolExecutionProgressData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record ToolExecutionProgressData(@JsonProperty("toolCallId") String toolCallId, - @JsonProperty("progressMessage") String progressMessage) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/ToolExecutionStartEvent.java b/src/main/java/com/github/copilot/sdk/events/ToolExecutionStartEvent.java deleted file mode 100644 index 850151825..000000000 --- a/src/main/java/com/github/copilot/sdk/events/ToolExecutionStartEvent.java +++ /dev/null @@ -1,40 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: tool.execution_start - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class ToolExecutionStartEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private ToolExecutionStartData data; - - @Override - public String getType() { - return "tool.execution_start"; - } - - public ToolExecutionStartData getData() { - return data; - } - - public void setData(ToolExecutionStartData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record ToolExecutionStartData(@JsonProperty("toolCallId") String toolCallId, - @JsonProperty("toolName") String toolName, @JsonProperty("arguments") Object arguments, - @JsonProperty("mcpServerName") String mcpServerName, @JsonProperty("mcpToolName") String mcpToolName, - @JsonProperty("parentToolCallId") String parentToolCallId) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/ToolUserRequestedEvent.java b/src/main/java/com/github/copilot/sdk/events/ToolUserRequestedEvent.java deleted file mode 100644 index 0a11e4568..000000000 --- a/src/main/java/com/github/copilot/sdk/events/ToolUserRequestedEvent.java +++ /dev/null @@ -1,38 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Event: tool.user_requested - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class ToolUserRequestedEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private ToolUserRequestedData data; - - @Override - public String getType() { - return "tool.user_requested"; - } - - public ToolUserRequestedData getData() { - return data; - } - - public void setData(ToolUserRequestedData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record ToolUserRequestedData(@JsonProperty("toolCallId") String toolCallId, - @JsonProperty("toolName") String toolName, @JsonProperty("arguments") Object arguments) { - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/UnknownSessionEvent.java b/src/main/java/com/github/copilot/sdk/events/UnknownSessionEvent.java deleted file mode 100644 index cbc19b317..000000000 --- a/src/main/java/com/github/copilot/sdk/events/UnknownSessionEvent.java +++ /dev/null @@ -1,74 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -/** - * Represents an unrecognized session event type received from the CLI. - *

- * When the CLI sends an event with a type that this SDK does not recognize (for - * example, an event type introduced in a newer CLI version), the SDK wraps it - * in an {@code UnknownSessionEvent} rather than dropping it. This ensures - * forward compatibility: event handlers can simply ignore unknown event types - * without the SDK crashing. - * - *

Example

- * - *
{@code
- * session.on(event -> {
- * 	if (event instanceof UnknownSessionEvent unknown) {
- * 		// Ignore events from newer CLI versions
- * 	}
- * });
- * }
- * - * @see AbstractSessionEvent - * @since 1.2.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class UnknownSessionEvent extends AbstractSessionEvent { - - private final String originalType; - - /** - * Creates an unknown session event with the given original type string. - * - * @param originalType - * the event type string received from the CLI; may be {@code null} - */ - public UnknownSessionEvent(String originalType) { - this.originalType = originalType != null ? originalType : "unknown"; - } - - /** - * No-arg constructor for internal use by the parser. - *

- * Creates an unknown event with {@code "unknown"} as the original type. Callers - * that need the original type should use {@link #UnknownSessionEvent(String)}. - */ - UnknownSessionEvent() { - this("unknown"); - } - - /** - * Returns {@code "unknown"} as the canonical type for all unrecognized events. - * - * @return always {@code "unknown"} - */ - @Override - public String getType() { - return "unknown"; - } - - /** - * Returns the original event type string as received from the CLI. - * - * @return the original type, never {@code null} - */ - public String getOriginalType() { - return originalType; - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/UserMessageEvent.java b/src/main/java/com/github/copilot/sdk/events/UserMessageEvent.java deleted file mode 100644 index d5e43f891..000000000 --- a/src/main/java/com/github/copilot/sdk/events/UserMessageEvent.java +++ /dev/null @@ -1,62 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -package com.github.copilot.sdk.events; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.Collections; -import java.util.List; - -/** - * Event: user.message - * - * @since 1.0.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public final class UserMessageEvent extends AbstractSessionEvent { - - @JsonProperty("data") - private UserMessageData data; - - @Override - public String getType() { - return "user.message"; - } - - public UserMessageData getData() { - return data; - } - - public void setData(UserMessageData data) { - this.data = data; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record UserMessageData(@JsonProperty("content") String content, - @JsonProperty("transformedContent") String transformedContent, - @JsonProperty("attachments") List attachments, @JsonProperty("source") String source) { - - /** Returns a defensive copy of the attachments list. */ - @Override - public List attachments() { - return attachments == null ? null : Collections.unmodifiableList(attachments); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record Attachment(@JsonProperty("type") String type, @JsonProperty("path") String path, - @JsonProperty("filePath") String filePath, @JsonProperty("displayName") String displayName, - @JsonProperty("text") String text, @JsonProperty("selection") Selection selection) { - - @JsonIgnoreProperties(ignoreUnknown = true) - public record Selection(@JsonProperty("start") Position start, @JsonProperty("end") Position end) { - - @JsonIgnoreProperties(ignoreUnknown = true) - public record Position(@JsonProperty("line") int line, @JsonProperty("character") int character) { - } - } - } - } -} diff --git a/src/main/java/com/github/copilot/sdk/events/package-info.java b/src/main/java/com/github/copilot/sdk/events/package-info.java deleted file mode 100644 index 6801543aa..000000000 --- a/src/main/java/com/github/copilot/sdk/events/package-info.java +++ /dev/null @@ -1,91 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -/** - * Event types emitted during Copilot session processing. - * - *

- * This package contains all event classes that can be emitted by a - * {@link com.github.copilot.sdk.CopilotSession} during message processing. - * Events provide real-time information about the session state, assistant - * responses, tool executions, and other activities. - * - *

Event Hierarchy

- *

- * All events extend {@link com.github.copilot.sdk.events.AbstractSessionEvent}, - * which provides common properties like event type and timestamp. - * - *

Key Event Types

- * - *

Message Events

- *
    - *
  • {@link com.github.copilot.sdk.events.UserMessageEvent} - User message was - * sent
  • - *
  • {@link com.github.copilot.sdk.events.AssistantMessageEvent} - Complete - * assistant response
  • - *
  • {@link com.github.copilot.sdk.events.AssistantMessageDeltaEvent} - - * Streaming response chunk
  • - *
  • {@link com.github.copilot.sdk.events.SystemMessageEvent} - System message - * added
  • - *
- * - *

Session Lifecycle Events

- *
    - *
  • {@link com.github.copilot.sdk.events.SessionStartEvent} - Session has - * started
  • - *
  • {@link com.github.copilot.sdk.events.SessionIdleEvent} - Session is idle - * (processing complete)
  • - *
  • {@link com.github.copilot.sdk.events.SessionErrorEvent} - An error - * occurred
  • - *
  • {@link com.github.copilot.sdk.events.SessionResumeEvent} - Session was - * resumed
  • - *
- * - *

Tool Execution Events

- *
    - *
  • {@link com.github.copilot.sdk.events.ToolExecutionStartEvent} - Tool - * execution started
  • - *
  • {@link com.github.copilot.sdk.events.ToolExecutionCompleteEvent} - Tool - * execution completed
  • - *
  • {@link com.github.copilot.sdk.events.ToolExecutionProgressEvent} - Tool - * execution progress update
  • - *
- * - *

Subagent Events

- *
    - *
  • {@link com.github.copilot.sdk.events.SubagentSelectedEvent} - Subagent - * was selected
  • - *
  • {@link com.github.copilot.sdk.events.SubagentStartedEvent} - Subagent - * execution started
  • - *
  • {@link com.github.copilot.sdk.events.SubagentCompletedEvent} - Subagent - * execution completed
  • - *
  • {@link com.github.copilot.sdk.events.SubagentFailedEvent} - Subagent - * execution failed
  • - *
- * - *

Usage Example

- * - *
{@code
- * session.on(evt -> {
- * 	if (evt instanceof AssistantMessageDeltaEvent delta) {
- * 		// Streaming response - print incrementally
- * 		System.out.print(delta.getData().deltaContent());
- * 	} else if (evt instanceof AssistantMessageEvent msg) {
- * 		// Complete response
- * 		System.out.println("\nFinal: " + msg.getData().content());
- * 	} else if (evt instanceof ToolExecutionStartEvent tool) {
- * 		System.out.println("Executing tool: " + tool.getData().toolName());
- * 	} else if (evt instanceof SessionIdleEvent) {
- * 		System.out.println("Session is idle");
- * 	} else if (evt instanceof SessionErrorEvent err) {
- * 		System.err.println("Error: " + err.getData().message());
- * 	}
- * });
- * }
- * - * @see com.github.copilot.sdk.CopilotSession#on(java.util.function.Consumer) - * @see com.github.copilot.sdk.events.AbstractSessionEvent - */ -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "DTOs for JSON deserialization - low risk") -package com.github.copilot.sdk.events; 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 139f5238b..2836cfd36 100644 --- a/src/main/java/com/github/copilot/sdk/json/ResumeSessionConfig.java +++ b/src/main/java/com/github/copilot/sdk/json/ResumeSessionConfig.java @@ -12,7 +12,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; -import com.github.copilot.sdk.events.AbstractSessionEvent; +import com.github.copilot.sdk.generated.SessionEvent; /** * Configuration for resuming an existing Copilot session. @@ -57,7 +57,7 @@ public class ResumeSessionConfig { private List skillDirectories; private List disabledSkills; private InfiniteSessionConfig infiniteSessions; - private Consumer onEvent; + private Consumer onEvent; private List commands; private ElicitationHandler onElicitationRequest; @@ -536,7 +536,7 @@ public ResumeSessionConfig setInfiniteSessions(InfiniteSessionConfig infiniteSes * * @return the event handler, or {@code null} if not set */ - public Consumer getOnEvent() { + public Consumer getOnEvent() { return onEvent; } @@ -552,7 +552,7 @@ public Consumer getOnEvent() { * the event handler to register before session resumption * @return this config for method chaining */ - public ResumeSessionConfig setOnEvent(Consumer onEvent) { + public ResumeSessionConfig setOnEvent(Consumer onEvent) { this.onEvent = onEvent; return this; } 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 5dcd39788..50e463e5a 100644 --- a/src/main/java/com/github/copilot/sdk/json/SessionConfig.java +++ b/src/main/java/com/github/copilot/sdk/json/SessionConfig.java @@ -12,7 +12,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; -import com.github.copilot.sdk.events.AbstractSessionEvent; +import com.github.copilot.sdk.generated.SessionEvent; /** * Configuration for creating a new Copilot session. @@ -57,7 +57,7 @@ public class SessionConfig { private List skillDirectories; private List disabledSkills; private String configDir; - private Consumer onEvent; + private Consumer onEvent; private List commands; private ElicitationHandler onElicitationRequest; @@ -573,7 +573,7 @@ public SessionConfig setConfigDir(String configDir) { * * @return the event handler, or {@code null} if not set */ - public Consumer getOnEvent() { + public Consumer getOnEvent() { return onEvent; } @@ -592,7 +592,7 @@ public Consumer getOnEvent() { * the event handler to register before session creation * @return this config instance for method chaining */ - public SessionConfig setOnEvent(Consumer onEvent) { + public SessionConfig setOnEvent(Consumer onEvent) { this.onEvent = onEvent; return this; } diff --git a/src/main/java/com/github/copilot/sdk/package-info.java b/src/main/java/com/github/copilot/sdk/package-info.java index 5c2777648..f775d575f 100644 --- a/src/main/java/com/github/copilot/sdk/package-info.java +++ b/src/main/java/com/github/copilot/sdk/package-info.java @@ -43,8 +43,8 @@ * *

Related Packages

*
    - *
  • {@link com.github.copilot.sdk.events} - Event types emitted during - * session processing
  • + *
  • {@link com.github.copilot.sdk.generated} - Auto-generated event types + * emitted during session processing
  • *
  • {@link com.github.copilot.sdk.json} - Configuration and data transfer * objects
  • *
diff --git a/src/site/markdown/advanced.md b/src/site/markdown/advanced.md index 5ae5c8f94..1209e2578 100644 --- a/src/site/markdown/advanced.md +++ b/src/site/markdown/advanced.md @@ -174,7 +174,7 @@ session.sendAndWait(new MessageOptions().setPrompt("Continue with the new model" The `reasoningEffort` parameter accepts `"low"`, `"medium"`, `"high"`, or `"xhigh"` for models that support reasoning. Pass `null` (or use the single-argument overload) to use the default. -The session emits a [`SessionModelChangeEvent`](apidocs/com/github/copilot/sdk/events/SessionModelChangeEvent.html) +The session emits a [`SessionModelChangeEvent`](apidocs/com/github/copilot/sdk/generated/SessionModelChangeEvent.html) when the switch completes, which you can observe with `session.on(SessionModelChangeEvent.class, event -> ...)`. See [CopilotSession.setModel()](apidocs/com/github/copilot/sdk/CopilotSession.html#setModel(java.lang.String)) Javadoc for details. @@ -675,7 +675,7 @@ Register an event handler *before* the `session.create` RPC is issued, ensuring When you register handlers with `session.on()` after `createSession()` returns, you may miss events emitted during session creation (e.g., `SessionStartEvent`). Use `SessionConfig.setOnEvent()` to guarantee delivery of all events from the very start: ```java -var events = new CopyOnWriteArrayList(); +var events = new CopyOnWriteArrayList(); var session = client.createSession( new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL) diff --git a/src/site/markdown/cookbook/error-handling.md b/src/site/markdown/cookbook/error-handling.md index 4240dc1ff..d077e95ca 100644 --- a/src/site/markdown/cookbook/error-handling.md +++ b/src/site/markdown/cookbook/error-handling.md @@ -32,7 +32,7 @@ jbang BasicErrorHandling.java ```java //DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.events.AssistantMessageEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.SessionConfig; @@ -101,7 +101,7 @@ public class SpecificErrorHandling { ```java //DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotSession; -import com.github.copilot.sdk.events.AssistantMessageEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -194,7 +194,7 @@ public class GracefulShutdown { ```java //DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.events.AssistantMessageEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.SessionConfig; @@ -226,7 +226,7 @@ public class TryWithResources { ```java //DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.events.AssistantMessageEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.SessionConfig; diff --git a/src/site/markdown/cookbook/managing-local-files.md b/src/site/markdown/cookbook/managing-local-files.md index 9535772b2..93758a969 100644 --- a/src/site/markdown/cookbook/managing-local-files.md +++ b/src/site/markdown/cookbook/managing-local-files.md @@ -36,10 +36,10 @@ jbang ManagingLocalFiles.java ```java //DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.events.AssistantMessageEvent; -import com.github.copilot.sdk.events.SessionIdleEvent; -import com.github.copilot.sdk.events.ToolExecutionCompleteEvent; -import com.github.copilot.sdk.events.ToolExecutionStartEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; +import com.github.copilot.sdk.generated.SessionIdleEvent; +import com.github.copilot.sdk.generated.ToolExecutionCompleteEvent; +import com.github.copilot.sdk.generated.ToolExecutionStartEvent; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.SessionConfig; diff --git a/src/site/markdown/cookbook/multiple-sessions.md b/src/site/markdown/cookbook/multiple-sessions.md index 776b6db6d..fee1f7159 100644 --- a/src/site/markdown/cookbook/multiple-sessions.md +++ b/src/site/markdown/cookbook/multiple-sessions.md @@ -32,7 +32,7 @@ jbang MultipleSessions.java ```java //DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.events.AssistantMessageEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.SessionConfig; diff --git a/src/site/markdown/cookbook/persisting-sessions.md b/src/site/markdown/cookbook/persisting-sessions.md index e653b8a6a..fc82bf965 100644 --- a/src/site/markdown/cookbook/persisting-sessions.md +++ b/src/site/markdown/cookbook/persisting-sessions.md @@ -32,7 +32,7 @@ jbang PersistingSessions.java ```java //DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.events.AssistantMessageEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.SessionConfig; @@ -129,8 +129,8 @@ public class DeleteSession { ```java //DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.events.AssistantMessageEvent; -import com.github.copilot.sdk.events.UserMessageEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; +import com.github.copilot.sdk.generated.UserMessageEvent; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.ResumeSessionConfig; diff --git a/src/site/markdown/cookbook/pr-visualization.md b/src/site/markdown/cookbook/pr-visualization.md index ad2939842..ce00e44e6 100644 --- a/src/site/markdown/cookbook/pr-visualization.md +++ b/src/site/markdown/cookbook/pr-visualization.md @@ -36,8 +36,8 @@ jbang PRVisualization.java github/copilot-sdk ```java //DEPS com.github:copilot-sdk-java:0.2.2-java.1 import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.events.AssistantMessageEvent; -import com.github.copilot.sdk.events.ToolExecutionStartEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; +import com.github.copilot.sdk.generated.ToolExecutionStartEvent; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.SessionConfig; diff --git a/src/site/markdown/documentation.md b/src/site/markdown/documentation.md index a96f66698..7b0c958e3 100644 --- a/src/site/markdown/documentation.md +++ b/src/site/markdown/documentation.md @@ -148,7 +148,7 @@ For the complete list of all event types, see [Event Types Reference](#Event_Typ ## Event Types Reference -The SDK supports event types organized by category. All events extend `AbstractSessionEvent`. +The SDK supports event types organized by category. All events extend `SessionEvent`. ### Session Events @@ -266,7 +266,7 @@ The SDK supports event types organized by category. All events extend `AbstractS | `ExitPlanModeRequestedEvent` | `exit_plan_mode.requested` | Exit from plan mode was requested | | `ExitPlanModeCompletedEvent` | `exit_plan_mode.completed` | Exit from plan mode completed | -See the [events package Javadoc](apidocs/com/github/copilot/sdk/events/package-summary.html) for detailed event data structures. +See the [generated package Javadoc](apidocs/com/github/copilot/sdk/generated/package-summary.html) for detailed event data structures. --- @@ -708,7 +708,7 @@ Complete list of all `SessionConfig` options for `createSession()`: | `configDir` | String | Custom configuration directory | [Config Dir](advanced.html#Custom_Configuration_Directory) | | `commands` | List<CommandDefinition> | Slash command definitions | [Slash Commands](advanced.html#Slash_Commands) | | `onElicitationRequest` | ElicitationHandler | Handler for incoming elicitation requests | [Elicitation](advanced.html#Elicitation_UI_Dialogs) | -| `onEvent` | Consumer<AbstractSessionEvent> | Event handler registered before session creation | [Early Event Registration](advanced.html#Early_Event_Registration) | +| `onEvent` | Consumer<SessionEvent> | Event handler registered before session creation | [Early Event Registration](advanced.html#Early_Event_Registration) | ### Cloning SessionConfig diff --git a/src/site/markdown/getting-started.md b/src/site/markdown/getting-started.md index 39bf43844..724b1a2dd 100644 --- a/src/site/markdown/getting-started.md +++ b/src/site/markdown/getting-started.md @@ -110,8 +110,8 @@ Right now, you wait for the complete response before seeing anything. Let's make ```java import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.events.AssistantMessageDeltaEvent; -import com.github.copilot.sdk.events.SessionIdleEvent; +import com.github.copilot.sdk.generated.AssistantMessageDeltaEvent; +import com.github.copilot.sdk.generated.SessionIdleEvent; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.SessionConfig; @@ -157,8 +157,8 @@ Now for the powerful part. Let's give Copilot the ability to call your code by d ```java import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.events.AssistantMessageDeltaEvent; -import com.github.copilot.sdk.events.SessionIdleEvent; +import com.github.copilot.sdk.generated.AssistantMessageDeltaEvent; +import com.github.copilot.sdk.generated.SessionIdleEvent; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.SessionConfig; @@ -239,8 +239,8 @@ Let's put it all together into a useful interactive assistant: ```java import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.events.AssistantMessageDeltaEvent; -import com.github.copilot.sdk.events.SessionIdleEvent; +import com.github.copilot.sdk.generated.AssistantMessageDeltaEvent; +import com.github.copilot.sdk.generated.SessionIdleEvent; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.SessionConfig; diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md index 60b96ce9d..a097da69e 100644 --- a/src/site/markdown/index.md +++ b/src/site/markdown/index.md @@ -37,8 +37,8 @@ implementation 'com.github:copilot-sdk-java:${project.version}' ```java import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.events.AssistantMessageEvent; -import com.github.copilot.sdk.events.SessionIdleEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; +import com.github.copilot.sdk.generated.SessionIdleEvent; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.SessionConfig; @@ -88,8 +88,8 @@ You can quickly try the SDK without setting up a full project using [JBang](http cat > hello-copilot.java << 'EOF' //DEPS com.github:copilot-sdk-java:${project.version} import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.events.AssistantMessageEvent; -import com.github.copilot.sdk.events.SessionIdleEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; +import com.github.copilot.sdk.generated.SessionIdleEvent; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.SessionConfig; diff --git a/src/test/java/com/github/copilot/sdk/ClosedSessionGuardTest.java b/src/test/java/com/github/copilot/sdk/ClosedSessionGuardTest.java index 069cd01cb..72d088a12 100644 --- a/src/test/java/com/github/copilot/sdk/ClosedSessionGuardTest.java +++ b/src/test/java/com/github/copilot/sdk/ClosedSessionGuardTest.java @@ -13,7 +13,7 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import com.github.copilot.sdk.events.AssistantMessageEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.SessionConfig; diff --git a/src/test/java/com/github/copilot/sdk/CompactionTest.java b/src/test/java/com/github/copilot/sdk/CompactionTest.java index ae8f8b1ea..da24dabd1 100644 --- a/src/test/java/com/github/copilot/sdk/CompactionTest.java +++ b/src/test/java/com/github/copilot/sdk/CompactionTest.java @@ -15,10 +15,10 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; -import com.github.copilot.sdk.events.AbstractSessionEvent; -import com.github.copilot.sdk.events.AssistantMessageEvent; -import com.github.copilot.sdk.events.SessionCompactionCompleteEvent; -import com.github.copilot.sdk.events.SessionCompactionStartEvent; +import com.github.copilot.sdk.generated.SessionEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; +import com.github.copilot.sdk.generated.SessionCompactionCompleteEvent; +import com.github.copilot.sdk.generated.SessionCompactionStartEvent; import com.github.copilot.sdk.json.InfiniteSessionConfig; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; @@ -71,7 +71,7 @@ void testShouldTriggerCompactionWithLowThresholdAndEmitEvents() throws Exception var config = new SessionConfig().setInfiniteSessions(infiniteConfig) .setOnPermissionRequest(PermissionHandler.APPROVE_ALL); - var events = new ArrayList(); + var events = new ArrayList(); var compactionCompleteLatch = new CountDownLatch(1); try (CopilotClient client = ctx.createClient()) { @@ -146,7 +146,7 @@ void testShouldNotEmitCompactionEventsWhenInfiniteSessionsDisabled() throws Exce var config = new SessionConfig().setInfiniteSessions(infiniteConfig) .setOnPermissionRequest(PermissionHandler.APPROVE_ALL); - var compactionEvents = new ArrayList(); + var compactionEvents = new ArrayList(); try (CopilotClient client = ctx.createClient()) { CopilotSession session = client.createSession(config).get(); diff --git a/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java b/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java index f3787705f..89f03de2d 100644 --- a/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java +++ b/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java @@ -15,7 +15,7 @@ import org.junit.jupiter.api.Test; -import com.github.copilot.sdk.events.AbstractSessionEvent; +import com.github.copilot.sdk.generated.SessionEvent; import com.github.copilot.sdk.json.CopilotClientOptions; import com.github.copilot.sdk.json.InfiniteSessionConfig; import com.github.copilot.sdk.json.MessageOptions; @@ -132,7 +132,7 @@ void sessionConfigListIndependence() { @Test void sessionConfigAgentAndOnEventCloned() { - Consumer handler = event -> { + Consumer handler = event -> { }; SessionConfig original = new SessionConfig(); original.setAgent("my-agent"); @@ -158,7 +158,7 @@ void resumeSessionConfigCloneBasic() { @Test void resumeSessionConfigAgentAndOnEventCloned() { - Consumer handler = event -> { + Consumer handler = event -> { }; ResumeSessionConfig original = new ResumeSessionConfig(); original.setAgent("my-agent"); diff --git a/src/test/java/com/github/copilot/sdk/CopilotClientTest.java b/src/test/java/com/github/copilot/sdk/CopilotClientTest.java index bc5869fda..d69f6cf74 100644 --- a/src/test/java/com/github/copilot/sdk/CopilotClientTest.java +++ b/src/test/java/com/github/copilot/sdk/CopilotClientTest.java @@ -14,11 +14,7 @@ import com.github.copilot.sdk.json.SessionLifecycleEvent; import com.github.copilot.sdk.json.SessionLifecycleEventTypes; -import java.io.BufferedReader; -import java.io.InputStreamReader; import java.lang.reflect.Field; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -38,53 +34,7 @@ public class CopilotClientTest { @BeforeAll static void setup() { - cliPath = getCliPath(); - } - - private static String getCliPath() { - // First, try to find 'copilot' in PATH - String copilotInPath = findCopilotInPath(); - if (copilotInPath != null) { - return copilotInPath; - } - - // Fall back to COPILOT_CLI_PATH environment variable - String envPath = System.getenv("COPILOT_CLI_PATH"); - if (envPath != null && !envPath.isEmpty()) { - return envPath; - } - - // Search for the CLI in the parent directories (nodejs module) - Path current = Paths.get(System.getProperty("user.dir")); - while (current != null) { - Path cliPath = current.resolve("nodejs/node_modules/@github/copilot/index.js"); - if (cliPath.toFile().exists()) { - return cliPath.toString(); - } - current = current.getParent(); - } - - return null; - } - - private static String findCopilotInPath() { - try { - // Use 'where' on Windows, 'which' on Unix-like systems - String command = System.getProperty("os.name").toLowerCase().contains("win") ? "where" : "which"; - var pb = new ProcessBuilder(command, "copilot"); - pb.redirectErrorStream(true); - Process process = pb.start(); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { - String line = reader.readLine(); - int exitCode = process.waitFor(); - if (exitCode == 0 && line != null && !line.isEmpty()) { - return line.trim(); - } - } - } catch (Exception e) { - // Ignore - copilot not found in PATH - } - return null; + cliPath = TestUtil.findCliPath(); } @Test @@ -133,10 +83,7 @@ void testCliUrlMutualExclusionWithCliPath() { @Test void testStartAndConnectUsingStdio() throws Exception { - if (cliPath == null) { - System.out.println("Skipping test: CLI not found"); - return; - } + assertNotNull(cliPath, "Copilot CLI not found in PATH or COPILOT_CLI_PATH"); try (var client = new CopilotClient(new CopilotClientOptions().setCliPath(cliPath).setUseStdio(true))) { client.start().get(); @@ -153,10 +100,7 @@ void testStartAndConnectUsingStdio() throws Exception { @Test void testShouldReportErrorWithStderrWhenCliFailsToStart() throws Exception { - if (cliPath == null) { - System.out.println("Skipping test: CLI not found"); - return; - } + assertNotNull(cliPath, "Copilot CLI not found in PATH or COPILOT_CLI_PATH"); var options = new CopilotClientOptions().setCliPath(cliPath) .setCliArgs(new String[]{"--nonexistent-flag-for-testing"}).setUseStdio(true); @@ -173,10 +117,7 @@ void testShouldReportErrorWithStderrWhenCliFailsToStart() throws Exception { @Test void testStartAndConnectUsingTcp() throws Exception { - if (cliPath == null) { - System.out.println("Skipping test: CLI not found"); - return; - } + assertNotNull(cliPath, "Copilot CLI not found in PATH or COPILOT_CLI_PATH"); try (var client = new CopilotClient(new CopilotClientOptions().setCliPath(cliPath).setUseStdio(false))) { client.start().get(); @@ -191,10 +132,7 @@ void testStartAndConnectUsingTcp() throws Exception { @Test void testForceStopWithoutCleanup() throws Exception { - if (cliPath == null) { - System.out.println("Skipping test: CLI not found"); - return; - } + assertNotNull(cliPath, "Copilot CLI not found in PATH or COPILOT_CLI_PATH"); try (var client = new CopilotClient(new CopilotClientOptions().setCliPath(cliPath))) { client.createSession(new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get(); @@ -448,10 +386,7 @@ void testForceStopWithNoConnectionCompletes() throws Exception { @Test void testCloseSessionAfterStoppingClientDoesNotThrow() throws Exception { - if (cliPath == null) { - System.out.println("Skipping test: CLI not found"); - return; - } + assertNotNull(cliPath, "Copilot CLI not found in PATH or COPILOT_CLI_PATH"); try (var client = new CopilotClient(new CopilotClientOptions().setCliPath(cliPath))) { var session = client diff --git a/src/test/java/com/github/copilot/sdk/CopilotSessionTest.java b/src/test/java/com/github/copilot/sdk/CopilotSessionTest.java index 39406d260..1e94c22a2 100644 --- a/src/test/java/com/github/copilot/sdk/CopilotSessionTest.java +++ b/src/test/java/com/github/copilot/sdk/CopilotSessionTest.java @@ -22,13 +22,14 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import com.github.copilot.sdk.events.AbstractSessionEvent; -import com.github.copilot.sdk.events.AbortEvent; -import com.github.copilot.sdk.events.AssistantMessageEvent; -import com.github.copilot.sdk.events.SessionIdleEvent; -import com.github.copilot.sdk.events.SessionStartEvent; -import com.github.copilot.sdk.events.ToolExecutionStartEvent; -import com.github.copilot.sdk.events.UserMessageEvent; +import com.github.copilot.sdk.generated.SessionEvent; +import com.github.copilot.sdk.generated.AbortEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; +import com.github.copilot.sdk.generated.SessionIdleEvent; +import com.github.copilot.sdk.generated.SessionStartEvent; +import com.github.copilot.sdk.generated.ToolExecutionStartEvent; +import com.github.copilot.sdk.generated.UserMessageEvent; +import com.github.copilot.sdk.generated.rpc.SessionRpc; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.ResumeSessionConfig; @@ -76,7 +77,7 @@ void testShouldReceiveSessionEvents_createAndDestroy() throws Exception { assertNotNull(session.getSessionId()); assertTrue(session.getSessionId().matches("^[a-f0-9-]+$")); - List messages = session.getMessages().get(); + List messages = session.getMessages().get(); assertFalse(messages.isEmpty()); assertTrue(messages.get(0) instanceof SessionStartEvent); @@ -143,7 +144,7 @@ void testShouldReceiveSessionEvents() throws Exception { CopilotSession session = client .createSession(new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get(); - List receivedEvents = new ArrayList<>(); + List receivedEvents = new ArrayList<>(); CompletableFuture idleReceived = new CompletableFuture<>(); session.on(evt -> { @@ -281,7 +282,7 @@ void testShouldResumeSessionUsingTheSameClient() throws Exception { assertEquals(sessionId, session2.getSessionId()); // Verify resumed session has the previous messages - List messages = session2.getMessages().get(60, TimeUnit.SECONDS); + List messages = session2.getMessages().get(60, TimeUnit.SECONDS); boolean hasAssistantMessage = messages.stream().filter(m -> m instanceof AssistantMessageEvent) .map(m -> (AssistantMessageEvent) m).anyMatch(m -> m.getData().content().contains("2")); assertTrue(hasAssistantMessage, "Should find previous assistant message containing 2"); @@ -329,7 +330,7 @@ void testShouldResumeSessionUsingNewClient() throws Exception { assertEquals(sessionId, session2.getSessionId()); // When resuming with a new client, validate messages contain expected types - List messages = session2.getMessages().get(60, TimeUnit.SECONDS); + List messages = session2.getMessages().get(60, TimeUnit.SECONDS); assertTrue(messages.stream().anyMatch(m -> m instanceof UserMessageEvent), "Should contain user.message event"); assertTrue(messages.stream().anyMatch(m -> "session.resume".equals(m.getType())), @@ -451,7 +452,7 @@ void testShouldAbortSession() throws Exception { sessionIdleFuture.get(30, TimeUnit.SECONDS); // The session should still be alive and usable after abort - List messages = session.getMessages().get(60, TimeUnit.SECONDS); + List messages = session.getMessages().get(60, TimeUnit.SECONDS); assertFalse(messages.isEmpty()); // Verify an abort event exists in messages @@ -849,4 +850,30 @@ void testShouldGetSessionMetadataById() throws Exception { session.close(); } } + + /** + * Verifies that {@link CopilotSession#getRpc()} returns a non-null + * {@link SessionRpc} wired to the session's ID and that all namespace fields + * are present. + */ + @Test + void testGetRpcReturnsSessionRpcWithCorrectSessionId() throws Exception { + ctx.configureForTest("session", "should_receive_session_events"); + + try (CopilotClient client = ctx.createClient()) { + CopilotSession session = client + .createSession(new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get(); + + SessionRpc rpc = session.getRpc(); + assertNotNull(rpc, "getRpc() must not return null"); + assertNotNull(rpc.agent, "SessionRpc.agent must not be null"); + assertNotNull(rpc.model, "SessionRpc.model must not be null"); + assertNotNull(rpc.tools, "SessionRpc.tools must not be null"); + assertNotNull(rpc.permissions, "SessionRpc.permissions must not be null"); + assertNotNull(rpc.commands, "SessionRpc.commands must not be null"); + assertNotNull(rpc.ui, "SessionRpc.ui must not be null"); + + session.close(); + } + } } diff --git a/src/test/java/com/github/copilot/sdk/ErrorHandlingTest.java b/src/test/java/com/github/copilot/sdk/ErrorHandlingTest.java index 8adc8a173..8c606930a 100644 --- a/src/test/java/com/github/copilot/sdk/ErrorHandlingTest.java +++ b/src/test/java/com/github/copilot/sdk/ErrorHandlingTest.java @@ -16,9 +16,9 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import com.github.copilot.sdk.events.AbstractSessionEvent; -import com.github.copilot.sdk.events.AssistantMessageEvent; -import com.github.copilot.sdk.events.SessionErrorEvent; +import com.github.copilot.sdk.generated.SessionEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; +import com.github.copilot.sdk.generated.SessionErrorEvent; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.SessionConfig; @@ -60,7 +60,7 @@ void testHandlesToolCallingErrors_toolErrorDoesNotCrashSession() throws Exceptio LOG.info("Running test: testHandlesToolCallingErrors_toolErrorDoesNotCrashSession"); ctx.configureForTest("tools", "handles_tool_calling_errors"); - var allEvents = new ArrayList(); + var allEvents = new ArrayList(); ToolDefinition errorTool = ToolDefinition.create("get_user_location", "Gets the user's location", Map.of("type", "object", "properties", Map.of()), (invocation) -> { @@ -84,7 +84,7 @@ void testHandlesToolCallingErrors_toolErrorDoesNotCrashSession() throws Exceptio assertNotNull(response, "Should receive a response even when tool fails"); // Should have received session.idle (indicating successful completion) - assertTrue(allEvents.stream().anyMatch(e -> e instanceof com.github.copilot.sdk.events.SessionIdleEvent), + assertTrue(allEvents.stream().anyMatch(e -> e instanceof com.github.copilot.sdk.generated.SessionIdleEvent), "Session should reach idle state after handling tool error"); session.close(); diff --git a/src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java b/src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java index 15904504a..bda67bbc9 100644 --- a/src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java +++ b/src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java @@ -21,7 +21,7 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import com.github.copilot.sdk.events.AssistantMessageEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; import com.github.copilot.sdk.json.CopilotClientOptions; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; diff --git a/src/test/java/com/github/copilot/sdk/ForwardCompatibilityTest.java b/src/test/java/com/github/copilot/sdk/ForwardCompatibilityTest.java index e64615141..06e2af5cf 100644 --- a/src/test/java/com/github/copilot/sdk/ForwardCompatibilityTest.java +++ b/src/test/java/com/github/copilot/sdk/ForwardCompatibilityTest.java @@ -10,11 +10,9 @@ import org.junit.jupiter.api.Test; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.copilot.sdk.events.AbstractSessionEvent; -import com.github.copilot.sdk.events.SessionEventParser; -import com.github.copilot.sdk.events.UnknownSessionEvent; -import com.github.copilot.sdk.events.UserMessageEvent; +import com.github.copilot.sdk.generated.SessionEvent; +import com.github.copilot.sdk.generated.UnknownSessionEvent; +import com.github.copilot.sdk.generated.UserMessageEvent; /** * Unit tests for forward-compatible handling of unknown session event types. @@ -24,8 +22,10 @@ */ public class ForwardCompatibilityTest { + private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = JsonRpcClient.getObjectMapper(); + @Test - void parse_knownEventType_returnsTypedEvent() { + void parse_knownEventType_returnsTypedEvent() throws Exception { String json = """ { "id": "00000000-0000-0000-0000-000000000001", @@ -34,15 +34,14 @@ void parse_knownEventType_returnsTypedEvent() { "data": { "content": "Hello" } } """; - var node = parse(json); - AbstractSessionEvent result = SessionEventParser.parse(node); + SessionEvent result = MAPPER.readValue(json, SessionEvent.class); assertInstanceOf(UserMessageEvent.class, result); assertEquals("user.message", result.getType()); } @Test - void parse_unknownEventType_returnsUnknownSessionEvent() { + void parse_unknownEventType_returnsUnknownSessionEvent() throws Exception { String json = """ { "id": "12345678-1234-1234-1234-123456789abc", @@ -51,15 +50,14 @@ void parse_unknownEventType_returnsUnknownSessionEvent() { "data": { "key": "value" } } """; - var node = parse(json); - AbstractSessionEvent result = SessionEventParser.parse(node); + SessionEvent result = MAPPER.readValue(json, SessionEvent.class); assertInstanceOf(UnknownSessionEvent.class, result); - assertEquals("unknown", result.getType()); + assertEquals("future.feature_from_server", result.getType()); } @Test - void parse_unknownEventType_preservesOriginalType() { + void parse_unknownEventType_preservesOriginalType() throws Exception { String json = """ { "id": "12345678-1234-1234-1234-123456789abc", @@ -68,15 +66,14 @@ void parse_unknownEventType_preservesOriginalType() { "data": {} } """; - var node = parse(json); - AbstractSessionEvent result = SessionEventParser.parse(node); + SessionEvent result = MAPPER.readValue(json, SessionEvent.class); assertInstanceOf(UnknownSessionEvent.class, result); - assertEquals("future.feature_from_server", ((UnknownSessionEvent) result).getOriginalType()); + assertEquals("future.feature_from_server", result.getType()); } @Test - void parse_unknownEventType_preservesBaseMetadata() { + void parse_unknownEventType_preservesBaseMetadata() throws Exception { String json = """ { "id": "12345678-1234-1234-1234-123456789abc", @@ -86,8 +83,7 @@ void parse_unknownEventType_preservesBaseMetadata() { "data": {} } """; - var node = parse(json); - AbstractSessionEvent result = SessionEventParser.parse(node); + SessionEvent result = MAPPER.readValue(json, SessionEvent.class); assertNotNull(result); assertEquals(UUID.fromString("12345678-1234-1234-1234-123456789abc"), result.getId()); @@ -96,28 +92,7 @@ void parse_unknownEventType_preservesBaseMetadata() { @Test void unknownSessionEvent_getType_returnsUnknown() { - var evt = new UnknownSessionEvent("some.future.type"); - assertEquals("unknown", evt.getType()); - } - - @Test - void unknownSessionEvent_getOriginalType_returnsOriginal() { - var evt = new UnknownSessionEvent("some.future.type"); - assertEquals("some.future.type", evt.getOriginalType()); - } - - @Test - void unknownSessionEvent_nullType_usesUnknown() { - var evt = new UnknownSessionEvent(null); + var evt = new UnknownSessionEvent(); assertEquals("unknown", evt.getType()); - assertEquals("unknown", evt.getOriginalType()); - } - - private com.fasterxml.jackson.databind.JsonNode parse(String json) { - try { - return new ObjectMapper().readTree(json); - } catch (Exception e) { - throw new RuntimeException(e); - } } } diff --git a/src/test/java/com/github/copilot/sdk/McpAndAgentsTest.java b/src/test/java/com/github/copilot/sdk/McpAndAgentsTest.java index 84aa3b341..5a362fe4e 100644 --- a/src/test/java/com/github/copilot/sdk/McpAndAgentsTest.java +++ b/src/test/java/com/github/copilot/sdk/McpAndAgentsTest.java @@ -15,7 +15,7 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import com.github.copilot.sdk.events.AssistantMessageEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; import com.github.copilot.sdk.json.CustomAgentConfig; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; diff --git a/src/test/java/com/github/copilot/sdk/MetadataApiTest.java b/src/test/java/com/github/copilot/sdk/MetadataApiTest.java index 580c58153..3a9120a52 100644 --- a/src/test/java/com/github/copilot/sdk/MetadataApiTest.java +++ b/src/test/java/com/github/copilot/sdk/MetadataApiTest.java @@ -5,16 +5,12 @@ package com.github.copilot.sdk; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.copilot.sdk.events.SessionEventParser; -import com.github.copilot.sdk.events.ToolExecutionProgressEvent; +import com.github.copilot.sdk.generated.SessionEvent; +import com.github.copilot.sdk.generated.ToolExecutionProgressEvent; import com.github.copilot.sdk.json.*; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; import static org.junit.jupiter.api.Assertions.*; @@ -26,56 +22,11 @@ public class MetadataApiTest { private static String cliPath; - private static final ObjectMapper MAPPER = new ObjectMapper(); + private static final ObjectMapper MAPPER = JsonRpcClient.getObjectMapper(); @BeforeAll static void setup() { - cliPath = getCliPath(); - } - - private static String getCliPath() { - // First, try to find 'copilot' in PATH - String copilotInPath = findCopilotInPath(); - if (copilotInPath != null) { - return copilotInPath; - } - - // Fall back to COPILOT_CLI_PATH environment variable - String envPath = System.getenv("COPILOT_CLI_PATH"); - if (envPath != null && !envPath.isEmpty()) { - return envPath; - } - - // Search for the CLI in the parent directories (nodejs module) - Path current = Paths.get(System.getProperty("user.dir")); - while (current != null) { - Path cliPath = current.resolve("nodejs/node_modules/@github/copilot/index.js"); - if (cliPath.toFile().exists()) { - return cliPath.toString(); - } - current = current.getParent(); - } - - return null; - } - - private static String findCopilotInPath() { - try { - String command = System.getProperty("os.name").toLowerCase().contains("win") ? "where" : "which"; - var pb = new ProcessBuilder(command, "copilot"); - pb.redirectErrorStream(true); - Process process = pb.start(); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { - String line = reader.readLine(); - int exitCode = process.waitFor(); - if (exitCode == 0 && line != null && !line.isEmpty()) { - return line.trim(); - } - } - } catch (Exception e) { - // Ignore - copilot not found in PATH - } - return null; + cliPath = TestUtil.findCliPath(); } // ===== ToolExecutionProgressEvent Tests ===== @@ -94,7 +45,7 @@ void testToolExecutionProgressEventParsing() throws Exception { } """; - var event = SessionEventParser.parse(MAPPER.readTree(json)); + var event = MAPPER.treeToValue(MAPPER.readTree(json), SessionEvent.class); assertNotNull(event); assertInstanceOf(ToolExecutionProgressEvent.class, event); @@ -108,7 +59,7 @@ void testToolExecutionProgressEventParsing() throws Exception { @Test void testToolExecutionProgressEventType() { - assertEquals("tool.execution_progress", ToolExecutionProgressEvent.TYPE); + assertEquals("tool.execution_progress", new ToolExecutionProgressEvent().getType()); } // ===== Response Type Deserialization Tests ===== @@ -262,10 +213,7 @@ void testGetModelsResponseDeserialization() throws Exception { @Test void testGetStatus() throws Exception { - if (cliPath == null) { - System.out.println("Skipping test: CLI not found"); - return; - } + assertNotNull(cliPath, "Copilot CLI not found in PATH or COPILOT_CLI_PATH"); try (var client = new CopilotClient(new CopilotClientOptions().setCliPath(cliPath).setUseStdio(true))) { client.start().get(); @@ -281,10 +229,7 @@ void testGetStatus() throws Exception { @Test void testGetAuthStatus() throws Exception { - if (cliPath == null) { - System.out.println("Skipping test: CLI not found"); - return; - } + assertNotNull(cliPath, "Copilot CLI not found in PATH or COPILOT_CLI_PATH"); try (var client = new CopilotClient(new CopilotClientOptions().setCliPath(cliPath).setUseStdio(true))) { client.start().get(); @@ -299,10 +244,7 @@ void testGetAuthStatus() throws Exception { @Test void testListModels() throws Exception { - if (cliPath == null) { - System.out.println("Skipping test: CLI not found"); - return; - } + assertNotNull(cliPath, "Copilot CLI not found in PATH or COPILOT_CLI_PATH"); try (var client = new CopilotClient(new CopilotClientOptions().setCliPath(cliPath).setUseStdio(true))) { client.start().get(); diff --git a/src/test/java/com/github/copilot/sdk/PermissionsTest.java b/src/test/java/com/github/copilot/sdk/PermissionsTest.java index af9347e33..75f73ddba 100644 --- a/src/test/java/com/github/copilot/sdk/PermissionsTest.java +++ b/src/test/java/com/github/copilot/sdk/PermissionsTest.java @@ -17,8 +17,8 @@ import org.junit.jupiter.api.Test; 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.generated.AssistantMessageEvent; +import com.github.copilot.sdk.generated.ToolExecutionCompleteEvent; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.PermissionRequest; import com.github.copilot.sdk.json.PermissionRequestResult; diff --git a/src/test/java/com/github/copilot/sdk/RpcWrappersTest.java b/src/test/java/com/github/copilot/sdk/RpcWrappersTest.java new file mode 100644 index 000000000..7d7b0dca4 --- /dev/null +++ b/src/test/java/com/github/copilot/sdk/RpcWrappersTest.java @@ -0,0 +1,471 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.copilot.sdk.generated.rpc.McpConfigAddParams; +import com.github.copilot.sdk.generated.rpc.McpDiscoverParams; +import com.github.copilot.sdk.generated.rpc.RpcCaller; +import com.github.copilot.sdk.generated.rpc.ServerRpc; +import com.github.copilot.sdk.generated.rpc.SessionAgentSelectParams; +import com.github.copilot.sdk.generated.rpc.SessionModelSwitchToParams; +import com.github.copilot.sdk.generated.rpc.SessionRpc; + +/** + * Unit tests for the generated RPC wrapper classes ({@link ServerRpc} and + * {@link SessionRpc}). Uses a simple in-memory {@link RpcCaller} stub to verify + * that: + *
    + *
  • The correct RPC method name is passed for each API call.
  • + *
  • {@link SessionRpc} automatically injects {@code sessionId} into every + * call.
  • + *
  • Session methods with extra params merge those params with the session + * ID.
  • + *
+ */ +class RpcWrappersTest { + + /** + * A simple stub {@link RpcCaller} that records every call made to it and + * returns a pre-configured result (or null). + */ + private static final class StubCaller implements RpcCaller { + + static record Call(String method, Object params) { + } + + final List calls = new ArrayList<>(); + Object nextResult = null; + + @Override + @SuppressWarnings("unchecked") + public CompletableFuture invoke(String method, Object params, Class resultType) { + calls.add(new Call(method, params)); + return CompletableFuture.completedFuture((T) nextResult); + } + } + + // ── ServerRpc tests ─────────────────────────────────────────────────────── + + @Test + void serverRpc_instantiates_with_all_namespace_fields() { + var stub = new StubCaller(); + var server = new ServerRpc(stub); + + assertNotNull(server.models); + assertNotNull(server.tools); + assertNotNull(server.account); + assertNotNull(server.mcp); + assertNotNull(server.mcp.config); // nested sub-namespace + assertNotNull(server.sessionFs); + assertNotNull(server.sessions); + } + + @Test + void serverRpc_models_list_invokes_correct_rpc_method() { + var stub = new StubCaller(); + stub.nextResult = null; // no result needed for method dispatch test + + var server = new ServerRpc(stub); + server.models.list(); + + assertEquals(1, stub.calls.size()); + assertEquals("models.list", stub.calls.get(0).method()); + } + + @Test + void serverRpc_ping_passes_params_directly() { + var stub = new StubCaller(); + var server = new ServerRpc(stub); + + var params = new com.github.copilot.sdk.generated.rpc.PingParams(null); + server.ping(params); + + assertEquals(1, stub.calls.size()); + assertEquals("ping", stub.calls.get(0).method()); + assertSame(params, stub.calls.get(0).params()); + } + + @Test + void serverRpc_mcp_config_list_invokes_correct_rpc_method() { + var stub = new StubCaller(); + var server = new ServerRpc(stub); + + server.mcp.config.list(); + + assertEquals(1, stub.calls.size()); + assertEquals("mcp.config.list", stub.calls.get(0).method()); + } + + @Test + void serverRpc_mcp_config_add_passes_params() { + var stub = new StubCaller(); + var server = new ServerRpc(stub); + + var params = new McpConfigAddParams("myServer", null); + server.mcp.config.add(params); + + assertEquals(1, stub.calls.size()); + assertEquals("mcp.config.add", stub.calls.get(0).method()); + assertSame(params, stub.calls.get(0).params()); + } + + @Test + void serverRpc_mcp_discover_passes_params() { + var stub = new StubCaller(); + var server = new ServerRpc(stub); + + var params = new McpDiscoverParams("/workspace"); + server.mcp.discover(params); + + assertEquals(1, stub.calls.size()); + assertEquals("mcp.discover", stub.calls.get(0).method()); + assertSame(params, stub.calls.get(0).params()); + } + + // ── SessionRpc tests ────────────────────────────────────────────────────── + + @Test + void sessionRpc_instantiates_with_all_namespace_fields() { + var stub = new StubCaller(); + var session = new SessionRpc(stub, "sess-001"); + + assertNotNull(session.model); + assertNotNull(session.mode); + assertNotNull(session.plan); + assertNotNull(session.workspace); + assertNotNull(session.fleet); + assertNotNull(session.agent); + assertNotNull(session.skills); + assertNotNull(session.mcp); + assertNotNull(session.plugins); + assertNotNull(session.extensions); + assertNotNull(session.tools); + assertNotNull(session.commands); + assertNotNull(session.ui); + assertNotNull(session.permissions); + assertNotNull(session.shell); + assertNotNull(session.history); + assertNotNull(session.usage); + } + + @Test + void sessionRpc_model_getCurrent_injects_sessionId_automatically() { + var stub = new StubCaller(); + var session = new SessionRpc(stub, "sess-abc"); + + session.model.getCurrent(); + + assertEquals(1, stub.calls.size()); + assertEquals("session.model.getCurrent", stub.calls.get(0).method()); + + // Params should be a Map containing sessionId + var params = stub.calls.get(0).params(); + assertInstanceOf(Map.class, params); + assertEquals("sess-abc", ((Map) params).get("sessionId")); + } + + @Test + void sessionRpc_model_switchTo_merges_sessionId_with_extra_params() { + var stub = new StubCaller(); + var session = new SessionRpc(stub, "sess-xyz"); + + // switchTo takes extra params beyond sessionId + var switchParams = new SessionModelSwitchToParams(null, "gpt-5", null, null); + session.model.switchTo(switchParams); + + assertEquals(1, stub.calls.size()); + assertEquals("session.model.switchTo", stub.calls.get(0).method()); + + // Params should be a JsonNode containing both sessionId and modelId + var params = stub.calls.get(0).params(); + assertInstanceOf(com.fasterxml.jackson.databind.node.ObjectNode.class, params); + var node = (com.fasterxml.jackson.databind.node.ObjectNode) params; + assertEquals("sess-xyz", node.get("sessionId").asText()); + assertEquals("gpt-5", node.get("modelId").asText()); + } + + @Test + void sessionRpc_agent_list_injects_sessionId() { + var stub = new StubCaller(); + var session = new SessionRpc(stub, "sess-999"); + + session.agent.list(); + + assertEquals(1, stub.calls.size()); + assertEquals("session.agent.list", stub.calls.get(0).method()); + + var params = stub.calls.get(0).params(); + assertInstanceOf(Map.class, params); + assertEquals("sess-999", ((Map) params).get("sessionId")); + } + + @Test + void sessionRpc_agent_select_merges_sessionId_with_extra_params() { + var stub = new StubCaller(); + var session = new SessionRpc(stub, "sess-select"); + + var selectParams = new SessionAgentSelectParams(null, "my-agent"); + session.agent.select(selectParams); + + assertEquals(1, stub.calls.size()); + assertEquals("session.agent.select", stub.calls.get(0).method()); + + var params = stub.calls.get(0).params(); + assertInstanceOf(com.fasterxml.jackson.databind.node.ObjectNode.class, params); + var node = (com.fasterxml.jackson.databind.node.ObjectNode) params; + assertEquals("sess-select", node.get("sessionId").asText()); + assertEquals("my-agent", node.get("name").asText()); + } + + @Test + void sessionRpc_different_sessions_have_different_sessionIds() { + var stub = new StubCaller(); + var session1 = new SessionRpc(stub, "sess-1"); + var session2 = new SessionRpc(stub, "sess-2"); + + session1.model.getCurrent(); + session2.model.getCurrent(); + + assertEquals(2, stub.calls.size()); + var params1 = (Map) stub.calls.get(0).params(); + var params2 = (Map) stub.calls.get(1).params(); + assertEquals("sess-1", params1.get("sessionId")); + assertEquals("sess-2", params2.get("sessionId")); + } + + @Test + void rpcCaller_is_implementable_as_anonymous_class_or_method_reference() { + // Verify RpcCaller can be used as an anonymous class + AtomicReference capturedMethod = new AtomicReference<>(); + RpcCaller caller = new RpcCaller() { + @Override + public CompletableFuture invoke(String method, Object params, Class resultType) { + capturedMethod.set(method); + return CompletableFuture.completedFuture(null); + } + }; + + var server = new ServerRpc(caller); + server.models.list(); + + assertEquals("models.list", capturedMethod.get()); + } + + @Test + void serverRpc_account_getQuota_invokes_correct_method() { + var stub = new StubCaller(); + var server = new ServerRpc(stub); + + server.account.getQuota(); + + assertEquals(1, stub.calls.size()); + assertEquals("account.getQuota", stub.calls.get(0).method()); + } + + // ── CopilotSession.getRpc() wiring tests ────────────────────────────────── + // These tests use a socket-pair backed JsonRpcClient (same pattern as + // RpcHandlerDispatcherTest) to construct a real CopilotSession and verify + // that getRpc() returns a correctly wired SessionRpc. + + @Test + void copilotSession_getRpc_returns_non_null_session_rpc() throws Exception { + try (var sockets = new SocketPair()) { + var rpc = sockets.client(); + var session = new CopilotSession("sess-unit", rpc); + + assertNotNull(session.getRpc()); + } + } + + @Test + void copilotSession_getRpc_sessionId_matches_session() throws Exception { + try (var sockets = new SocketPair()) { + var rpc = sockets.client(); + var stub = sockets.stubServer(); + var session = new CopilotSession("sess-test-id", rpc); + + // Call any no-arg session method via getRpc() to verify sessionId injection + session.getRpc().agent.list(); + + // Drain the sent message from the stub server + var sent = stub.readOneMessage(); + assertEquals("session.agent.list", sent.get("method").asText()); + assertEquals("sess-test-id", sent.get("params").get("sessionId").asText()); + } + } + + @Test + void copilotSession_getRpc_updates_when_sessionId_changes() throws Exception { + try (var sockets = new SocketPair()) { + var rpc = sockets.client(); + var stub = sockets.stubServer(); + var session = new CopilotSession("old-id", rpc); + + // Simulate server returning a different sessionId (v2 CLI behaviour) + session.setActiveSessionId("new-id"); + + session.getRpc().agent.list(); + + var sent = stub.readOneMessage(); + assertEquals("new-id", sent.get("params").get("sessionId").asText(), + "getRpc() should reflect the updated sessionId"); + } + } + + @Test + void copilotSession_getRpc_all_namespace_fields_present() throws Exception { + try (var sockets = new SocketPair()) { + var rpc = sockets.client(); + var session = new CopilotSession("sess-ns", rpc); + + var sessionRpc = session.getRpc(); + assertNotNull(sessionRpc.model); + assertNotNull(sessionRpc.agent); + assertNotNull(sessionRpc.skills); + assertNotNull(sessionRpc.tools); + assertNotNull(sessionRpc.permissions); + assertNotNull(sessionRpc.commands); + assertNotNull(sessionRpc.ui); + } + } + + @Test + void copilotSession_getRpc_is_lazy_and_cached() throws Exception { + // Verify lazy init: getRpc() returns the same instance on repeated calls + // (caches rather than allocating a new SessionRpc per call). + try (var sockets = new SocketPair()) { + var rpc = sockets.client(); + var session = new CopilotSession("sess-cache", rpc); + + var first = session.getRpc(); + var second = session.getRpc(); + assertNotNull(first); + assertSame(first, second, "getRpc() must return the cached instance when sessionId has not changed"); + } + } + + @Test + void copilotSession_getRpc_returns_new_instance_after_sessionId_change() throws Exception { + // Verify that after setActiveSessionId() the old cached instance is discarded + // and the next getRpc() call produces a fresh SessionRpc with the new ID. + try (var sockets = new SocketPair()) { + var rpc = sockets.client(); + var stub = sockets.stubServer(); + var session = new CopilotSession("old-id", rpc); + + var before = session.getRpc(); + session.setActiveSessionId("new-id"); + var after = session.getRpc(); + + assertNotNull(before); + assertNotNull(after); + assertNotSame(before, after, "getRpc() must return a new instance after sessionId changes"); + + // Confirm the new instance uses the new sessionId + after.agent.list(); + var sent = stub.readOneMessage(); + assertEquals("new-id", sent.get("params").get("sessionId").asText()); + } + } + + @Test + void copilotClient_getRpc_throws_before_start() { + // CopilotClient.getRpc() should throw before start() is called. + var client = new CopilotClient(); + assertThrows(IllegalStateException.class, client::getRpc, + "getRpc() must throw IllegalStateException if called before start()"); + } + + /** + * Helper that creates a loopback socket pair. The client side is used by + * {@link JsonRpcClient}; the server side can be read to inspect outbound + * messages. + */ + private static final class SocketPair implements AutoCloseable { + + private static final ObjectMapper MAPPER = JsonRpcClient.getObjectMapper(); + + private final java.net.Socket clientSocket; + private final java.net.Socket serverSocket; + private final JsonRpcClient rpcClient; + + SocketPair() throws Exception { + try (var ss = new java.net.ServerSocket(0)) { + clientSocket = new java.net.Socket("localhost", ss.getLocalPort()); + serverSocket = ss.accept(); + } + serverSocket.setSoTimeout(3000); + rpcClient = JsonRpcClient.fromSocket(clientSocket); + } + + JsonRpcClient client() { + return rpcClient; + } + + StubServer stubServer() { + return new StubServer(serverSocket); + } + + @Override + public void close() throws Exception { + rpcClient.close(); + clientSocket.close(); + serverSocket.close(); + } + } + + /** + * Reads raw JSON-RPC messages written to the server side of the socket. + */ + private static final class StubServer { + + private static final ObjectMapper MAPPER = JsonRpcClient.getObjectMapper(); + + private final java.io.InputStream in; + + StubServer(java.net.Socket socket) { + try { + this.in = socket.getInputStream(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Reads one JSON-RPC message (Content-Length framed) from the stream. + */ + com.fasterxml.jackson.databind.JsonNode readOneMessage() throws Exception { + // Read Content-Length header + var header = new StringBuilder(); + int b; + while ((b = in.read()) != -1) { + if (b == '\n' && header.toString().endsWith("\r")) { + break; + } + header.append((char) b); + } + // Skip blank line + in.read(); // '\r' + in.read(); // '\n' + + String hdr = header.toString().trim(); + int colon = hdr.indexOf(':'); + int len = Integer.parseInt(hdr.substring(colon + 1).trim()); + byte[] body = in.readNBytes(len); + return MAPPER.readTree(body); + } + } +} diff --git a/src/test/java/com/github/copilot/sdk/SessionEventParserTest.java b/src/test/java/com/github/copilot/sdk/SessionEventDeserializationTest.java similarity index 90% rename from src/test/java/com/github/copilot/sdk/SessionEventParserTest.java rename to src/test/java/com/github/copilot/sdk/SessionEventDeserializationTest.java index 4a63bb243..baa572f35 100644 --- a/src/test/java/com/github/copilot/sdk/SessionEventParserTest.java +++ b/src/test/java/com/github/copilot/sdk/SessionEventDeserializationTest.java @@ -7,34 +7,29 @@ import static org.junit.jupiter.api.Assertions.*; import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; import org.junit.jupiter.api.Test; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.generated.*; /** - * Tests for session event parsing. + * Tests for session event deserialization. *

* These are unit tests that verify JSON deserialization works correctly for all * event types supported by the SDK. *

*/ -public class SessionEventParserTest { +public class SessionEventDeserializationTest { - private static final ObjectMapper MAPPER = new ObjectMapper(); + private static final ObjectMapper MAPPER = JsonRpcClient.getObjectMapper(); /** - * Helper to convert a JSON string to a JsonNode and parse via - * {@link SessionEventParser#parse(JsonNode)}. + * Helper to parse a JSON string directly to a {@link SessionEvent}. */ - private static AbstractSessionEvent parseJson(String json) throws Exception { - JsonNode node = MAPPER.readTree(json); - return SessionEventParser.parse(node); + private static SessionEvent parseJson(String json) throws Exception { + return MAPPER.readValue(json, SessionEvent.class); } // ========================================================================= @@ -53,7 +48,7 @@ void testParseSessionStartEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionStartEvent.class, event); assertEquals("session.start", event.getType()); @@ -73,7 +68,7 @@ void testParseSessionResumeEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionResumeEvent.class, event); assertEquals("session.resume", event.getType()); @@ -92,7 +87,7 @@ void testParseSessionErrorEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionErrorEvent.class, event); assertEquals("session.error", event.getType()); @@ -112,7 +107,7 @@ void testParseSessionIdleEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionIdleEvent.class, event); assertEquals("session.idle", event.getType()); @@ -130,7 +125,7 @@ void testParseSessionInfoEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionInfoEvent.class, event); assertEquals("session.info", event.getType()); @@ -152,7 +147,7 @@ void testParseSessionModelChangeEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionModelChangeEvent.class, event); assertEquals("session.model_change", event.getType()); @@ -170,7 +165,7 @@ void testParseSessionModeChangedEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionModeChangedEvent.class, event); assertEquals("session.mode_changed", event.getType()); @@ -187,7 +182,7 @@ void testParseSessionPlanChangedEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionPlanChangedEvent.class, event); assertEquals("session.plan_changed", event.getType()); @@ -205,7 +200,7 @@ void testParseSessionWorkspaceFileChangedEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionWorkspaceFileChangedEvent.class, event); assertEquals("session.workspace_file_changed", event.getType()); @@ -222,7 +217,7 @@ void testParseSessionHandoffEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionHandoffEvent.class, event); assertEquals("session.handoff", event.getType()); @@ -239,7 +234,7 @@ void testParseSessionTruncationEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionTruncationEvent.class, event); assertEquals("session.truncation", event.getType()); @@ -256,7 +251,7 @@ void testParseSessionSnapshotRewindEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionSnapshotRewindEvent.class, event); assertEquals("session.snapshot_rewind", event.getType()); @@ -273,7 +268,7 @@ void testParseSessionUsageInfoEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionUsageInfoEvent.class, event); assertEquals("session.usage_info", event.getType()); @@ -288,7 +283,7 @@ void testParseSessionCompactionStartEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionCompactionStartEvent.class, event); assertEquals("session.compaction_start", event.getType()); @@ -303,7 +298,7 @@ void testParseSessionCompactionCompleteEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionCompactionCompleteEvent.class, event); assertEquals("session.compaction_complete", event.getType()); @@ -325,7 +320,7 @@ void testParseUserMessageEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(UserMessageEvent.class, event); assertEquals("user.message", event.getType()); @@ -342,7 +337,7 @@ void testParsePendingMessagesModifiedEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(PendingMessagesModifiedEvent.class, event); assertEquals("pending_messages.modified", event.getType()); @@ -363,7 +358,7 @@ void testParseAssistantTurnStartEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(AssistantTurnStartEvent.class, event); assertEquals("assistant.turn_start", event.getType()); @@ -383,7 +378,7 @@ void testParseAssistantIntentEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(AssistantIntentEvent.class, event); assertEquals("assistant.intent", event.getType()); @@ -401,7 +396,7 @@ void testParseAssistantReasoningEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(AssistantReasoningEvent.class, event); assertEquals("assistant.reasoning", event.getType()); @@ -423,7 +418,7 @@ void testParseAssistantReasoningDeltaEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(AssistantReasoningDeltaEvent.class, event); assertEquals("assistant.reasoning_delta", event.getType()); @@ -441,7 +436,7 @@ void testParseAssistantMessageEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(AssistantMessageEvent.class, event); assertEquals("assistant.message", event.getType()); @@ -462,7 +457,7 @@ void testParseAssistantMessageDeltaEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(AssistantMessageDeltaEvent.class, event); assertEquals("assistant.message_delta", event.getType()); @@ -479,7 +474,7 @@ void testParseAssistantTurnEndEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(AssistantTurnEndEvent.class, event); assertEquals("assistant.turn_end", event.getType()); @@ -498,7 +493,7 @@ void testParseAssistantUsageEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(AssistantUsageEvent.class, event); assertEquals("assistant.usage", event.getType()); @@ -520,7 +515,7 @@ void testParseToolUserRequestedEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(ToolUserRequestedEvent.class, event); assertEquals("tool.user_requested", event.getType()); @@ -538,7 +533,7 @@ void testParseToolExecutionStartEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(ToolExecutionStartEvent.class, event); assertEquals("tool.execution_start", event.getType()); @@ -556,7 +551,7 @@ void testParseToolExecutionPartialResultEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(ToolExecutionPartialResultEvent.class, event); assertEquals("tool.execution_partial_result", event.getType()); @@ -574,7 +569,7 @@ void testParseToolExecutionProgressEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(ToolExecutionProgressEvent.class, event); assertEquals("tool.execution_progress", event.getType()); @@ -596,7 +591,7 @@ void testParseToolExecutionCompleteEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(ToolExecutionCompleteEvent.class, event); assertEquals("tool.execution_complete", event.getType()); @@ -623,7 +618,7 @@ void testParseSubagentStartedEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SubagentStartedEvent.class, event); assertEquals("subagent.started", event.getType()); @@ -645,7 +640,7 @@ void testParseSubagentCompletedEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SubagentCompletedEvent.class, event); assertEquals("subagent.completed", event.getType()); @@ -663,7 +658,7 @@ void testParseSubagentFailedEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SubagentFailedEvent.class, event); assertEquals("subagent.failed", event.getType()); @@ -680,7 +675,7 @@ void testParseSubagentSelectedEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SubagentSelectedEvent.class, event); assertEquals("subagent.selected", event.getType()); @@ -703,7 +698,7 @@ void testParseHookStartEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(HookStartEvent.class, event); assertEquals("hook.start", event.getType()); @@ -725,7 +720,7 @@ void testParseHookEndEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(HookEndEvent.class, event); assertEquals("hook.end", event.getType()); @@ -746,7 +741,7 @@ void testParseAbortEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(AbortEvent.class, event); assertEquals("abort", event.getType()); @@ -763,7 +758,7 @@ void testParseSystemMessageEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SystemMessageEvent.class, event); assertEquals("system.message", event.getType()); @@ -790,17 +785,18 @@ void testParseSessionShutdownEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionShutdownEvent.class, event); assertEquals("session.shutdown", event.getType()); var shutdownEvent = (SessionShutdownEvent) event; - assertEquals(SessionShutdownEvent.ShutdownType.ROUTINE, shutdownEvent.getData().shutdownType()); - assertEquals(5, shutdownEvent.getData().totalPremiumRequests()); + assertEquals(SessionShutdownEvent.SessionShutdownEventData.SessionShutdownEventDataShutdownType.ROUTINE, + shutdownEvent.getData().shutdownType()); + assertEquals(5.0, shutdownEvent.getData().totalPremiumRequests()); assertEquals("gpt-4", shutdownEvent.getData().currentModel()); assertNotNull(shutdownEvent.getData().codeChanges()); - assertEquals(10, shutdownEvent.getData().codeChanges().linesAdded()); + assertEquals(10.0, shutdownEvent.getData().codeChanges().linesAdded()); } @Test @@ -817,7 +813,7 @@ void testParseSkillInvokedEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SkillInvokedEvent.class, event); assertEquals("skill.invoked", event.getType()); @@ -844,36 +840,27 @@ void testParseUnknownEventType() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event, "Unknown event types should return an UnknownSessionEvent"); - assertInstanceOf(com.github.copilot.sdk.events.UnknownSessionEvent.class, event, + assertInstanceOf(com.github.copilot.sdk.generated.UnknownSessionEvent.class, event, "Unknown event types should return UnknownSessionEvent for forward compatibility"); - assertEquals("unknown", event.getType()); - assertEquals("unknown.event.type", - ((com.github.copilot.sdk.events.UnknownSessionEvent) event).getOriginalType()); + assertEquals("unknown.event.type", event.getType(), + "UnknownSessionEvent should preserve the original type from JSON"); } @Test void testParseMissingTypeField() throws Exception { - // Suppress logging for this test since missing type logs a WARNING - Logger parserLogger = Logger.getLogger(SessionEventParser.class.getName()); - Level originalLevel = parserLogger.getLevel(); - parserLogger.setLevel(Level.OFF); - - try { - String json = """ - { - "data": { - "content": "Hello" - } + String json = """ + { + "data": { + "content": "Hello" } - """; + } + """; - AbstractSessionEvent event = parseJson(json); - assertNull(event, "Events without type field should return null"); - } finally { - parserLogger.setLevel(originalLevel); - } + SessionEvent event = parseJson(json); + assertNotNull(event, "Events without type field should return UnknownSessionEvent"); + assertInstanceOf(com.github.copilot.sdk.generated.UnknownSessionEvent.class, event); } @Test @@ -890,26 +877,18 @@ void testParseEventWithUnknownFields() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event, "Events with unknown fields should still parse"); assertInstanceOf(SessionIdleEvent.class, event); } @Test void testParseEmptyJson() throws Exception { - // Suppress logging for this test since empty JSON logs a WARNING - Logger parserLogger = Logger.getLogger(SessionEventParser.class.getName()); - Level originalLevel = parserLogger.getLevel(); - parserLogger.setLevel(Level.OFF); - - try { - String json = "{}"; - - AbstractSessionEvent event = parseJson(json); - assertNull(event, "Empty JSON should return null due to missing type"); - } finally { - parserLogger.setLevel(originalLevel); - } + String json = "{}"; + + SessionEvent event = parseJson(json); + assertNotNull(event, "Empty JSON should return UnknownSessionEvent"); + assertInstanceOf(com.github.copilot.sdk.generated.UnknownSessionEvent.class, event); } // ========================================================================= @@ -936,14 +915,14 @@ void testParseAllEventTypes() throws Exception { "data": {} } """.formatted(type); - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event, "Event type '%s' should parse".formatted(type)); assertEquals(type, event.getType(), "Parsed type should match for '%s'".formatted(type)); } } // ========================================================================= - // AbstractSessionEvent base fields + // SessionEvent base fields // ========================================================================= @Test @@ -957,7 +936,7 @@ void testParseBaseFieldsId() throws Exception { } """.formatted(uuid); - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertEquals(UUID.fromString(uuid), event.getId()); } @@ -973,7 +952,7 @@ void testParseBaseFieldsParentId() throws Exception { } """.formatted(parentUuid); - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertEquals(UUID.fromString(parentUuid), event.getParentId()); } @@ -988,7 +967,7 @@ void testParseBaseFieldsEphemeral() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertTrue(event.getEphemeral()); } @@ -1003,7 +982,7 @@ void testParseBaseFieldsTimestamp() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertNotNull(event.getTimestamp()); } @@ -1025,7 +1004,7 @@ void testParseBaseFieldsAllTogether() throws Exception { } """.formatted(uuid, parentUuid); - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertEquals(UUID.fromString(uuid), event.getId()); assertEquals(UUID.fromString(parentUuid), event.getParentId()); @@ -1044,7 +1023,7 @@ void testParseBaseFieldsNullWhenAbsent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertNull(event.getId()); assertNull(event.getParentId()); @@ -1152,7 +1131,7 @@ void testSessionHandoffEventAllFields() throws Exception { "type": "session.handoff", "data": { "handoffTime": "2025-05-01T10:00:00Z", - "sourceType": "cli", + "sourceType": "remote", "repository": { "owner": "my-org", "name": "my-repo", @@ -1169,7 +1148,8 @@ void testSessionHandoffEventAllFields() throws Exception { assertNotNull(event); var data = event.getData(); assertNotNull(data.handoffTime()); - assertEquals("cli", data.sourceType()); + assertEquals(SessionHandoffEvent.SessionHandoffEventData.SessionHandoffEventDataSourceType.REMOTE, + data.sourceType()); assertEquals("additional context", data.context()); assertEquals("handoff summary", data.summary()); assertEquals("remote-sess-1", data.remoteSessionId()); @@ -1296,7 +1276,9 @@ void testSessionShutdownEventAllFields() throws Exception { "filesModified": ["a.java", "b.java", "c.java"] }, "modelMetrics": { - "avgLatency": 200 + "gpt-4": { + "requests": {"count": 5.0, "cost": 2.5} + } }, "currentModel": "gpt-4-turbo" } @@ -1306,7 +1288,8 @@ void testSessionShutdownEventAllFields() throws Exception { var event = (SessionShutdownEvent) parseJson(json); assertNotNull(event); var data = event.getData(); - assertEquals(SessionShutdownEvent.ShutdownType.ERROR, data.shutdownType()); + assertEquals(SessionShutdownEvent.SessionShutdownEventData.SessionShutdownEventDataShutdownType.ERROR, + data.shutdownType()); assertEquals("OOM", data.errorReason()); assertEquals(10.0, data.totalPremiumRequests()); assertEquals(5000.5, data.totalApiDurationMs()); @@ -1468,8 +1451,14 @@ void testAssistantUsageEventAllFields() throws Exception { "providerCallId": "prov-1", "parentToolCallId": "ptc-usage", "quotaSnapshots": { - "premium": 100, - "standard": 500 + "premium": { + "entitlementRequests": 100.0, + "usedRequests": 25.0 + }, + "standard": { + "entitlementRequests": 500.0, + "usedRequests": 150.0 + } }, "copilotUsage": { "totalNanoAiu": 1234567.0, @@ -1538,9 +1527,9 @@ void testAssistantUsageEventWithNullQuotaSnapshots() throws Exception { assertEquals("gpt-4-turbo", data.model()); assertEquals(500.0, data.inputTokens()); assertEquals(200.0, data.outputTokens()); - // quotaSnapshots should return an empty map, not null - assertNotNull(data.quotaSnapshots()); - assertTrue(data.quotaSnapshots().isEmpty()); + // quotaSnapshots is null when absent in JSON (generated class uses nullable + // fields) + assertNull(data.quotaSnapshots()); } @Test @@ -1788,20 +1777,27 @@ void testUserMessageEventAllFieldsWithAttachments() throws Exception { assertNotNull(data.attachments()); assertEquals(1, data.attachments().size()); - var att = data.attachments().get(0); - assertEquals("file", att.type()); - assertEquals("/src/Main.java", att.path()); - assertEquals("/full/src/Main.java", att.filePath()); - assertEquals("Main.java", att.displayName()); - assertEquals("public class Main {}", att.text()); - - assertNotNull(att.selection()); - assertNotNull(att.selection().start()); - assertNotNull(att.selection().end()); - assertEquals(1, att.selection().start().line()); - assertEquals(0, att.selection().start().character()); - assertEquals(5, att.selection().end().line()); - assertEquals(10, att.selection().end().character()); + @SuppressWarnings("unchecked") + var att = (java.util.Map) data.attachments().get(0); + assertEquals("file", att.get("type")); + assertEquals("/src/Main.java", att.get("path")); + assertEquals("/full/src/Main.java", att.get("filePath")); + assertEquals("Main.java", att.get("displayName")); + assertEquals("public class Main {}", att.get("text")); + + @SuppressWarnings("unchecked") + var selection = (java.util.Map) att.get("selection"); + assertNotNull(selection); + @SuppressWarnings("unchecked") + var selStart = (java.util.Map) selection.get("start"); + @SuppressWarnings("unchecked") + var selEnd = (java.util.Map) selection.get("end"); + assertNotNull(selStart); + assertNotNull(selEnd); + assertEquals(1, ((Number) selStart.get("line")).intValue()); + assertEquals(0, ((Number) selStart.get("character")).intValue()); + assertEquals(5, ((Number) selEnd.get("line")).intValue()); + assertEquals(10, ((Number) selEnd.get("character")).intValue()); } @Test @@ -1905,10 +1901,10 @@ void testSubagentSelectedEventAllFields() throws Exception { assertEquals("best-agent", data.agentName()); assertEquals("Best Agent", data.agentDisplayName()); assertNotNull(data.tools()); - assertEquals(3, data.tools().length); - assertEquals("read", data.tools()[0]); - assertEquals("write", data.tools()[1]); - assertEquals("search", data.tools()[2]); + assertEquals(3, data.tools().size()); + assertEquals("read", data.tools().get(0)); + assertEquals("write", data.tools().get(1)); + assertEquals("search", data.tools().get(2)); } // ========================================================================= @@ -2024,9 +2020,9 @@ void testSystemMessageEventAllFields() throws Exception { assertNotNull(event); var data = event.getData(); assertEquals("System notification", data.content()); - assertEquals("warning", data.type()); - assertNotNull(data.metadata()); - assertEquals(2, data.metadata().size()); + // Note: "type" field in JSON is not mapped in generated class; metadata fields + // "severity"/"source" are ignored + assertNotNull(data); } @Test @@ -2060,7 +2056,7 @@ void testParseEventWithNullData() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionIdleEvent.class, event); } @@ -2073,25 +2069,11 @@ void testParseEventWithMissingData() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionIdleEvent.class, event); } - @Test - void testParseNullJsonNode() throws Exception { - Logger parserLogger = Logger.getLogger(SessionEventParser.class.getName()); - Level originalLevel = parserLogger.getLevel(); - parserLogger.setLevel(Level.OFF); - - try { - AbstractSessionEvent event = SessionEventParser.parse((JsonNode) null); - assertNull(event, "Null JsonNode should return null"); - } finally { - parserLogger.setLevel(originalLevel); - } - } - // ========================================================================= // Additional data assertion tests // ========================================================================= @@ -2167,7 +2149,8 @@ void testParseJsonNodeSessionShutdownWithCodeChanges() throws Exception { var event = (SessionShutdownEvent) parseJson(json); assertNotNull(event); - assertEquals(SessionShutdownEvent.ShutdownType.ROUTINE, event.getData().shutdownType()); + assertEquals(SessionShutdownEvent.SessionShutdownEventData.SessionShutdownEventDataShutdownType.ROUTINE, + event.getData().shutdownType()); assertEquals(100.0, event.getData().codeChanges().linesAdded()); assertEquals(1, event.getData().codeChanges().filesModified().size()); } @@ -2197,11 +2180,18 @@ void testParseJsonNodeUserMessageWithAttachment() throws Exception { var event = (UserMessageEvent) parseJson(json); assertNotNull(event); assertEquals(1, event.getData().attachments().size()); - var att = event.getData().attachments().get(0); - assertEquals("code", att.type()); - assertEquals("snippet.py", att.displayName()); - assertEquals(0, att.selection().start().line()); - assertEquals(14, att.selection().end().character()); + @SuppressWarnings("unchecked") + var att = (java.util.Map) event.getData().attachments().get(0); + assertEquals("code", att.get("type")); + assertEquals("snippet.py", att.get("displayName")); + @SuppressWarnings("unchecked") + var selection = (java.util.Map) att.get("selection"); + @SuppressWarnings("unchecked") + var start = (java.util.Map) selection.get("start"); + @SuppressWarnings("unchecked") + var end = (java.util.Map) selection.get("end"); + assertEquals(0, ((Number) start.get("line")).intValue()); + assertEquals(14, ((Number) end.get("character")).intValue()); } @Test @@ -2266,7 +2256,9 @@ void testParsePermissionRequestedEvent() throws Exception { assertEquals("permission.requested", event.getType()); assertEquals("perm-req-456", event.getData().requestId()); assertNotNull(event.getData().permissionRequest()); - assertEquals("shell", event.getData().permissionRequest().getKind()); + @SuppressWarnings("unchecked") + var permReq = (java.util.Map) event.getData().permissionRequest(); + assertEquals("shell", permReq.get("kind")); } @Test @@ -2287,7 +2279,9 @@ void testParsePermissionCompletedEvent() throws Exception { assertNotNull(event); assertEquals("permission.completed", event.getType()); assertEquals("perm-req-456", event.getData().requestId()); - assertEquals("approved", event.getData().result().kind()); + assertEquals( + PermissionCompletedEvent.PermissionCompletedEventData.PermissionCompletedEventDataResult.PermissionCompletedEventDataResultKind.APPROVED, + event.getData().result().kind()); } @Test @@ -2346,7 +2340,7 @@ void testParseExitPlanModeRequestedEvent() throws Exception { assertEquals("exit_plan_mode.requested", event.getType()); assertEquals("plan-req-001", event.getData().requestId()); assertEquals("Plan is ready", event.getData().summary()); - assertEquals(3, event.getData().actions().length); + assertEquals(3, event.getData().actions().size()); assertEquals("approve", event.getData().recommendedAction()); } @@ -2399,7 +2393,7 @@ void testParseCapabilitiesChangedEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(CapabilitiesChangedEvent.class, event); assertEquals("capabilities.changed", event.getType()); @@ -2410,8 +2404,8 @@ void testParseCapabilitiesChangedEvent() throws Exception { assertTrue(castedEvent.getData().ui().elicitation()); // Verify setData round-trip - var newData = new CapabilitiesChangedEvent.CapabilitiesChangedData( - new CapabilitiesChangedEvent.CapabilitiesChangedUi(false)); + var newData = new CapabilitiesChangedEvent.CapabilitiesChangedEventData( + new CapabilitiesChangedEvent.CapabilitiesChangedEventData.CapabilitiesChangedEventDataUi(false)); castedEvent.setData(newData); assertFalse(castedEvent.getData().ui().elicitation()); } @@ -2430,7 +2424,7 @@ void testParseCommandExecuteEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(CommandExecuteEvent.class, event); assertEquals("command.execute", event.getType()); @@ -2443,7 +2437,7 @@ void testParseCommandExecuteEvent() throws Exception { assertEquals("production", castedEvent.getData().args()); // Verify setData round-trip - castedEvent.setData(new CommandExecuteEvent.CommandExecuteData("req-002", "/rollback", "rollback", null)); + castedEvent.setData(new CommandExecuteEvent.CommandExecuteEventData("req-002", "/rollback", "rollback", null)); assertEquals("req-002", castedEvent.getData().requestId()); } @@ -2470,7 +2464,7 @@ void testParseElicitationRequestedEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(ElicitationRequestedEvent.class, event); assertEquals("elicitation.requested", event.getType()); @@ -2481,7 +2475,8 @@ void testParseElicitationRequestedEvent() throws Exception { assertEquals("tc-123", castedEvent.getData().toolCallId()); assertEquals("mcp_tool", castedEvent.getData().elicitationSource()); assertEquals("Please provide your name", castedEvent.getData().message()); - assertEquals("form", castedEvent.getData().mode()); + assertEquals(ElicitationRequestedEvent.ElicitationRequestedEventData.ElicitationRequestedEventDataMode.FORM, + castedEvent.getData().mode()); assertNotNull(castedEvent.getData().requestedSchema()); assertEquals("object", castedEvent.getData().requestedSchema().type()); assertNotNull(castedEvent.getData().requestedSchema().properties()); @@ -2489,10 +2484,13 @@ void testParseElicitationRequestedEvent() throws Exception { assertTrue(castedEvent.getData().requestedSchema().required().contains("name")); // Verify setData round-trip - castedEvent.setData(new ElicitationRequestedEvent.ElicitationRequestedData("elix-002", null, null, "Enter URL", - "url", null, "https://example.com")); + castedEvent.setData( + new ElicitationRequestedEvent.ElicitationRequestedEventData("elix-002", null, null, "Enter URL", + ElicitationRequestedEvent.ElicitationRequestedEventData.ElicitationRequestedEventDataMode.URL, + null, "https://example.com")); assertEquals("elix-002", castedEvent.getData().requestId()); - assertEquals("url", castedEvent.getData().mode()); + assertEquals(ElicitationRequestedEvent.ElicitationRequestedEventData.ElicitationRequestedEventDataMode.URL, + castedEvent.getData().mode()); } @Test @@ -2509,14 +2507,14 @@ void testParseSessionContextChangedEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionContextChangedEvent.class, event); assertEquals("session.context_changed", event.getType()); var castedEvent = (SessionContextChangedEvent) event; assertNotNull(castedEvent.getData()); - assertEquals("/home/user/project", castedEvent.getData().getCwd()); + assertEquals("/home/user/project", castedEvent.getData().cwd()); // Verify setData round-trip castedEvent.setData(null); @@ -2534,7 +2532,7 @@ void testParseSessionTaskCompleteEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SessionTaskCompleteEvent.class, event); assertEquals("session.task_complete", event.getType()); @@ -2544,7 +2542,7 @@ void testParseSessionTaskCompleteEvent() throws Exception { assertEquals("Task completed successfully", castedEvent.getData().summary()); // Verify setData round-trip - castedEvent.setData(new SessionTaskCompleteEvent.SessionTaskCompleteData("New summary")); + castedEvent.setData(new SessionTaskCompleteEvent.SessionTaskCompleteEventData("New summary", null)); assertEquals("New summary", castedEvent.getData().summary()); } @@ -2557,7 +2555,7 @@ void testParseSubagentDeselectedEvent() throws Exception { } """; - AbstractSessionEvent event = parseJson(json); + SessionEvent event = parseJson(json); assertNotNull(event); assertInstanceOf(SubagentDeselectedEvent.class, event); assertEquals("subagent.deselected", event.getType()); @@ -2566,7 +2564,7 @@ void testParseSubagentDeselectedEvent() throws Exception { assertNotNull(castedEvent.getData()); // Verify setData round-trip - castedEvent.setData(new SubagentDeselectedEvent.SubagentDeselectedData()); + castedEvent.setData(new SubagentDeselectedEvent.SubagentDeselectedEventData()); assertNotNull(castedEvent.getData()); } } diff --git a/src/test/java/com/github/copilot/sdk/SessionEventHandlingTest.java b/src/test/java/com/github/copilot/sdk/SessionEventHandlingTest.java index 2e9da4fd2..73ed6fffa 100644 --- a/src/test/java/com/github/copilot/sdk/SessionEventHandlingTest.java +++ b/src/test/java/com/github/copilot/sdk/SessionEventHandlingTest.java @@ -21,10 +21,10 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import com.github.copilot.sdk.events.AbstractSessionEvent; -import com.github.copilot.sdk.events.AssistantMessageEvent; -import com.github.copilot.sdk.events.SessionIdleEvent; -import com.github.copilot.sdk.events.SessionStartEvent; +import com.github.copilot.sdk.generated.SessionEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; +import com.github.copilot.sdk.generated.SessionIdleEvent; +import com.github.copilot.sdk.generated.SessionStartEvent; /** * Unit tests for session event handling API. @@ -52,7 +52,7 @@ private CopilotSession createTestSession() throws Exception { @Test void testGenericEventHandler() { - var receivedEvents = new ArrayList(); + var receivedEvents = new ArrayList(); session.on(event -> receivedEvents.add(event)); @@ -179,7 +179,8 @@ void testHandlerReceivesCorrectEventData() { }); SessionStartEvent startEvent = createSessionStartEvent(); - startEvent.setData(new SessionStartEvent.SessionStartData("my-session-123", 0, null, null, null, null)); + startEvent.setData(new SessionStartEvent.SessionStartEventData("my-session-123", null, null, null, null, null, + null, null, null, null)); dispatchEvent(startEvent); AssistantMessageEvent msgEvent = createAssistantMessageEvent("Test content"); @@ -417,7 +418,7 @@ void testDefaultPolicyPropagatesAndLogs() { @Test void testCustomEventErrorHandlerReceivesEventAndException() { - var capturedEvents = new ArrayList(); + var capturedEvents = new ArrayList(); var capturedExceptions = new ArrayList(); Logger sessionLogger = Logger.getLogger(CopilotSession.class.getName()); @@ -547,7 +548,7 @@ void testSetEventErrorHandlerToNullRestoresDefaultBehavior() { @Test void testErrorHandlerReceivesCorrectEventType() { - var capturedEvents = new ArrayList(); + var capturedEvents = new ArrayList(); Logger sessionLogger = Logger.getLogger(CopilotSession.class.getName()); Level originalLevel = sessionLogger.getLevel(); @@ -838,9 +839,9 @@ void testErrorHandlerThrowingStopsRegardlessOfPolicy() { // Helper methods // ==================================================================== - private void dispatchEvent(AbstractSessionEvent event) { + private void dispatchEvent(SessionEvent event) { try { - Method dispatchMethod = CopilotSession.class.getDeclaredMethod("dispatchEvent", AbstractSessionEvent.class); + Method dispatchMethod = CopilotSession.class.getDeclaredMethod("dispatchEvent", SessionEvent.class); dispatchMethod.setAccessible(true); dispatchMethod.invoke(session, event); } catch (Exception e) { @@ -855,14 +856,16 @@ private SessionStartEvent createSessionStartEvent() { private SessionStartEvent createSessionStartEvent(String sessionId) { var event = new SessionStartEvent(); - var data = new SessionStartEvent.SessionStartData(sessionId, 0, null, null, null, null); + var data = new SessionStartEvent.SessionStartEventData(sessionId, null, null, null, null, null, null, null, + null, null); event.setData(data); return event; } private AssistantMessageEvent createAssistantMessageEvent(String content) { var event = new AssistantMessageEvent(); - var data = new AssistantMessageEvent.AssistantMessageData(null, content, null, null, null, null, null, null); + var data = new AssistantMessageEvent.AssistantMessageEventData(null, content, null, null, null, null, null, + null, null, null, null); event.setData(data); return event; } diff --git a/src/test/java/com/github/copilot/sdk/SessionEventsE2ETest.java b/src/test/java/com/github/copilot/sdk/SessionEventsE2ETest.java index dad3f5907..d13c84247 100644 --- a/src/test/java/com/github/copilot/sdk/SessionEventsE2ETest.java +++ b/src/test/java/com/github/copilot/sdk/SessionEventsE2ETest.java @@ -16,15 +16,15 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import com.github.copilot.sdk.events.AbstractSessionEvent; -import com.github.copilot.sdk.events.AssistantMessageEvent; -import com.github.copilot.sdk.events.AssistantTurnEndEvent; -import com.github.copilot.sdk.events.AssistantTurnStartEvent; -import com.github.copilot.sdk.events.AssistantUsageEvent; -import com.github.copilot.sdk.events.SessionIdleEvent; -import com.github.copilot.sdk.events.ToolExecutionCompleteEvent; -import com.github.copilot.sdk.events.ToolExecutionStartEvent; -import com.github.copilot.sdk.events.UserMessageEvent; +import com.github.copilot.sdk.generated.SessionEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; +import com.github.copilot.sdk.generated.AssistantTurnEndEvent; +import com.github.copilot.sdk.generated.AssistantTurnStartEvent; +import com.github.copilot.sdk.generated.AssistantUsageEvent; +import com.github.copilot.sdk.generated.SessionIdleEvent; +import com.github.copilot.sdk.generated.ToolExecutionCompleteEvent; +import com.github.copilot.sdk.generated.ToolExecutionStartEvent; +import com.github.copilot.sdk.generated.UserMessageEvent; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.SessionConfig; @@ -62,7 +62,7 @@ void testShouldReceiveSessionEvents_assistantTurnEvents() throws Exception { // Use existing session snapshot that emits turn events ctx.configureForTest("session", "should_receive_session_events"); - var allEvents = new ArrayList(); + var allEvents = new ArrayList(); try (CopilotClient client = ctx.createClient()) { CopilotSession session = client @@ -197,7 +197,7 @@ void testShouldReceiveSessionEvents_sessionIdleAfterMessage() throws Exception { // Use existing session snapshot ctx.configureForTest("session", "should_receive_session_events"); - var allEvents = new ArrayList(); + var allEvents = new ArrayList(); try (CopilotClient client = ctx.createClient()) { CopilotSession session = client @@ -240,12 +240,24 @@ void testInvokesBuiltInTools_eventOrderDuringToolExecution() throws Exception { ctx.configureForTest("tools", "invokes_built_in_tools"); var eventTypes = new ArrayList(); + // Use a separate completion signal so we know when THIS handler has seen + // session.idle, rather than relying on sendAndWait's internal subscription. + // sendAndWait also listens for session.idle internally. Because eventHandlers + // is a ConcurrentHashMap Set (non-deterministic iteration order), the + // sendAndWait handler can fire BEFORE this listener and unblock the test + // thread before session.idle has been added to eventTypes — a race condition. + var idleReceived = new java.util.concurrent.CompletableFuture(); try (CopilotClient client = ctx.createClient()) { CopilotSession session = client .createSession(new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get(); - session.on(event -> eventTypes.add(event.getType())); + session.on(event -> { + eventTypes.add(event.getType()); + if (event instanceof SessionIdleEvent) { + idleReceived.complete(null); + } + }); // Create the README.md file expected by the snapshot - must have ONLY one line // to match the snapshot's expected tool response: "1. # ELIZA, the only chatbot @@ -257,6 +269,11 @@ void testInvokesBuiltInTools_eventOrderDuringToolExecution() throws Exception { session.sendAndWait(new MessageOptions().setPrompt("What's the first line of README.md in this directory?")) .get(60, TimeUnit.SECONDS); + // Wait for this listener to also receive session.idle. sendAndWait can return + // slightly before our listener sees the event due to concurrent dispatch + // ordering. + idleReceived.get(5, TimeUnit.SECONDS); + // Verify expected event types are present assertTrue(eventTypes.contains("user.message"), "Should have user.message"); assertTrue(eventTypes.contains("assistant.turn_start"), "Should have assistant.turn_start"); diff --git a/src/test/java/com/github/copilot/sdk/SkillsTest.java b/src/test/java/com/github/copilot/sdk/SkillsTest.java index e2900a927..7d27af3b8 100644 --- a/src/test/java/com/github/copilot/sdk/SkillsTest.java +++ b/src/test/java/com/github/copilot/sdk/SkillsTest.java @@ -17,7 +17,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import com.github.copilot.sdk.events.AssistantMessageEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.SessionConfig; diff --git a/src/test/java/com/github/copilot/sdk/StreamingFidelityTest.java b/src/test/java/com/github/copilot/sdk/StreamingFidelityTest.java index d6bae399d..f3f597652 100644 --- a/src/test/java/com/github/copilot/sdk/StreamingFidelityTest.java +++ b/src/test/java/com/github/copilot/sdk/StreamingFidelityTest.java @@ -16,9 +16,9 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import com.github.copilot.sdk.events.AbstractSessionEvent; -import com.github.copilot.sdk.events.AssistantMessageDeltaEvent; -import com.github.copilot.sdk.events.AssistantMessageEvent; +import com.github.copilot.sdk.generated.SessionEvent; +import com.github.copilot.sdk.generated.AssistantMessageDeltaEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.ResumeSessionConfig; @@ -63,13 +63,13 @@ void testShouldProduceDeltaEventsWhenStreamingIsEnabled() throws Exception { CopilotSession session = client.createSession( new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setStreaming(true)).get(); - List events = new ArrayList<>(); + List events = new ArrayList<>(); session.on(events::add); session.sendAndWait(new MessageOptions().setPrompt("Count from 1 to 5, separated by commas.")).get(60, TimeUnit.SECONDS); - List types = events.stream().map(AbstractSessionEvent::getType).toList(); + List types = events.stream().map(SessionEvent::getType).toList(); // Should have streaming deltas before the final message List deltaEvents = events.stream() @@ -110,7 +110,7 @@ void testShouldNotProduceDeltasWhenStreamingIsDisabled() throws Exception { new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setStreaming(false)) .get(); - List events = new ArrayList<>(); + List events = new ArrayList<>(); session.on(events::add); session.sendAndWait(new MessageOptions().setPrompt("Say 'hello world'.")).get(60, TimeUnit.SECONDS); @@ -156,7 +156,7 @@ void testShouldProduceDeltasAfterSessionResume() throws Exception { CopilotSession session2 = newClient.resumeSession(sessionId, new ResumeSessionConfig() .setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setStreaming(true)).get(); - List events = new ArrayList<>(); + List events = new ArrayList<>(); session2.on(events::add); AssistantMessageEvent answer = session2 diff --git a/src/test/java/com/github/copilot/sdk/TestUtil.java b/src/test/java/com/github/copilot/sdk/TestUtil.java new file mode 100644 index 000000000..72f214a8b --- /dev/null +++ b/src/test/java/com/github/copilot/sdk/TestUtil.java @@ -0,0 +1,101 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot.sdk; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * Shared test utilities for locating the Copilot CLI binary. + */ +final class TestUtil { + + private TestUtil() { + } + + /** + * Locates a launchable Copilot CLI executable. + *

+ * Resolution order: + *

    + *
  1. Search the system PATH using {@code where.exe} (Windows) or {@code which} + * (Linux/macOS).
  2. + *
  3. Fall back to the {@code COPILOT_CLI_PATH} environment variable.
  4. + *
  5. Walk parent directories looking for + * {@code nodejs/node_modules/@github/copilot/index.js}.
  6. + *
+ * + *

+ * Why iterate all PATH results? On Windows, {@code where.exe copilot} + * can return multiple candidates. The first hit is often a Linux ELF binary + * bundled inside the VS Code Insiders extension directory — it exists on disk + * but cannot be executed by {@link ProcessBuilder} (CreateProcess error 193). + * This method tries each candidate with {@code --version} and returns the first + * one that actually launches, skipping non-executable entries. + * + * @return the absolute path to a launchable {@code copilot} binary, or + * {@code null} if none was found + */ + static String findCliPath() { + String copilotInPath = findCopilotInPath(); + if (copilotInPath != null) { + return copilotInPath; + } + + String envPath = System.getenv("COPILOT_CLI_PATH"); + if (envPath != null && !envPath.isEmpty()) { + return envPath; + } + + Path current = Paths.get(System.getProperty("user.dir")); + while (current != null) { + Path cliPath = current.resolve("nodejs/node_modules/@github/copilot/index.js"); + if (cliPath.toFile().exists()) { + return cliPath.toString(); + } + current = current.getParent(); + } + + return null; + } + + /** + * Searches the system PATH for a launchable {@code copilot} executable. + *

+ * Uses {@code where.exe} on Windows and {@code which} on Unix-like systems. On + * Windows, {@code where.exe} may return multiple results (e.g. a Linux ELF + * binary, a {@code .bat} wrapper, a {@code .cmd} wrapper). This method iterates + * all results and returns the first one that {@link ProcessBuilder} can + * actually start. + */ + private static String findCopilotInPath() { + try { + String command = System.getProperty("os.name").toLowerCase().contains("win") ? "where" : "which"; + var pb = new ProcessBuilder(command, "copilot"); + pb.redirectErrorStream(true); + Process process = pb.start(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + int exitCode = process.waitFor(); + if (exitCode != 0) { + return null; + } + var lines = reader.lines().map(String::trim).filter(l -> !l.isEmpty()).toList(); + for (String candidate : lines) { + try { + new ProcessBuilder(candidate, "--version").redirectErrorStream(true).start().destroyForcibly(); + return candidate; + } catch (Exception launchFailed) { + // Not launchable on this platform — try next candidate + } + } + } + } catch (Exception e) { + // Ignore - copilot not found in PATH + } + return null; + } +} diff --git a/src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java b/src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java index c5ed3af81..b771f65b2 100644 --- a/src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java +++ b/src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java @@ -15,7 +15,7 @@ import org.junit.jupiter.api.Test; -import com.github.copilot.sdk.events.AssistantMessageEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; /** diff --git a/src/test/java/com/github/copilot/sdk/ToolsTest.java b/src/test/java/com/github/copilot/sdk/ToolsTest.java index 538da74d2..1c4eaaf58 100644 --- a/src/test/java/com/github/copilot/sdk/ToolsTest.java +++ b/src/test/java/com/github/copilot/sdk/ToolsTest.java @@ -20,7 +20,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInfo; -import com.github.copilot.sdk.events.AssistantMessageEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; import com.github.copilot.sdk.json.PermissionHandler; import com.github.copilot.sdk.json.PermissionRequest; diff --git a/src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java b/src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java index 3c79ac263..524026e69 100644 --- a/src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java +++ b/src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java @@ -12,7 +12,7 @@ import org.junit.jupiter.api.Test; -import com.github.copilot.sdk.events.AssistantMessageEvent; +import com.github.copilot.sdk.generated.AssistantMessageEvent; import com.github.copilot.sdk.json.MessageOptions; /** From 0beb1d85d79fcc54cf665cb418c5b7181ada1d6e Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Fri, 17 Apr 2026 18:23:47 -0400 Subject: [PATCH 78/80] Prevent local IDEs from editing generated code --- .github/copilot-instructions.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 08f0a5758..d02978421 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -213,6 +213,8 @@ Test method names are converted to lowercase snake_case for snapshot filenames t ### What NOT to Modify +- **DO NOT** edit, create, or delete any file under `src/generated/java/` — these are **auto-generated** by `scripts/codegen/java.ts` and will be overwritten. To update generated code, run `mvn generate-sources -Pcodegen` or trigger the `update-copilot-dependency.yml` workflow. + If you need to get a new version of the schemas, run `mvn generate-sources -Pupdate-schemas-from-npm-artifact` before running the code generator. - **DO NOT** edit `.github/agents/` directory - these contain instructions for other agents - **DO NOT** modify `target/` directory - this contains build artifacts - **DO NOT** edit `pom.xml` dependencies without careful consideration - this SDK has minimal dependencies by design From add35a6da45e328f801124e40c215c09fc6f41c3 Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Fri, 17 Apr 2026 18:46:13 -0400 Subject: [PATCH 79/80] Apply Copilot review comments. modified: scripts/codegen/java.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### 18:24 Prompt Consider these Copilot review comments, all about `java.ts` - Lines 167 - 178 > The generator passes required=true when generating container element/value types (List, Map). This can produce illegal Java generic types like List / Map when the schema item type is integer/boolean/number, causing generated code not to compile. Fix by ensuring container element/value types are always boxed (e.g., call schemaTypeToJava(..., false, ...) for items and additionalProperties value schemas, or add a dedicated “box primitives in generics” step). ### 18:29 Prompt Consider these Copilot review comments, all about `java.ts` - Lines 193 - 201 > The generator passes required=true when generating container element/value types (List, Map). This can produce illegal Java generic types like List / Map when the schema item type is integer/boolean/number, causing generated code not to compile. Fix by ensuring container element/value types are always boxed (e.g., call schemaTypeToJava(..., false, ...) for items and additionalProperties value schemas, or add a dedicated “box primitives in generics” step). ### 18:31 Prompt Consider these Copilot review comments, all about `java.ts` - Lines 1258 - 1261 > RpcMapper.INSTANCE is a plain new ObjectMapper() with no modules. Generated RPC DTOs can include OffsetDateTime (your type mapping emits it for format: date-time), and ObjectMapper.valueToTree(...) used by session wrappers can fail without JavaTimeModule registered. Fix by configuring this shared mapper consistently (e.g., register com.fasterxml.jackson.datatype.jsr310.JavaTimeModule, and align any other ObjectMapper features needed by the SDK). ### 18:34 Prompt Consider these Copilot review comments, all about `java.ts` - Lines 1202 - 1207 > This comment is likely incorrect/misleading: Java lambdas can generally target a functional interface whose single abstract method is generic (the compiler can still infer the type parameter from the call site). Consider removing this claim or rephrasing it to a neutral recommendation (e.g., “method reference is typical/clear”) so consumers aren’t discouraged from valid usage. Copilot suggests: ```typescript lines.push(` * (e.g., a {@code JsonRpcClient} instance). A method reference is typically the clearest`); lines.push(` * way to adapt a generic {@code invoke} method to this interface:`); lines.push(` *

{@code`);
    lines.push(` * RpcCaller caller = jsonRpcClient::invoke;`);
    lines.push(` * }
`); ``` What can we do about this? ### 18:36 Prompt Consider these Copilot review comments, all about `java.ts` - Lines 848 - 854 > For session-scoped RPC methods with additional params, the generated *Params records still include a sessionId field (because they’re generated directly from the schema), but the wrapper then overwrites sessionId via _p.put("sessionId", this.sessionId). This duplication is confusing for API consumers and makes the param records look “callable” with arbitrary session IDs when they are not. Consider adjusting generation so sessionId is omitted from session-scoped params records (and only injected by SessionRpc), or documenting clearly in the generated Javadoc that any provided sessionId is ignored/overridden. Copilot suggests: ```typescript * Return the wrapper-visible parameter property names for a method. * For session-scoped wrappers, sessionId is injected by SessionRpc and is not * considered a user-supplied parameter. */ function wrapperParamPropertyNames(method: RpcMethodNode, isSession: boolean): string[] { if (!method.params || typeof method.params !== "object") return []; const props = method.params.properties ?? {}; return Object.keys(props).filter((k) => !(isSession && k === "sessionId")); } /** * Return the params class name if the method has wrapper-visible properties * (i.e. user-supplied parameters after filtering out injected sessionId for * session-scoped wrappers). */ function wrapperParamsClassName(method: RpcMethodNode, isSession: boolean): string | null { const userProps = wrapperParamPropertyNames(method, isSession); ``` What can we do about this? ### 18:40 Prompt Consider these Copilot review comments, all about `java.ts` - Lines 903 - 915 > For session-scoped RPC methods with additional params, the generated *Params records still include a sessionId field (because they’re generated directly from the schema), but the wrapper then overwrites sessionId via _p.put("sessionId", this.sessionId). This duplication is confusing for API consumers and makes the param records look “callable” with arbitrary session IDs when they are not. Consider adjusting generation so sessionId is omitted from session-scoped params records (and only injected by SessionRpc), or documenting clearly in the generated Javadoc that any provided sessionId is ignored/overridden. What can we do about this? This seems the same as the previous comment. No? modified: src/generated/java/com/github/copilot/sdk/generated/rpc/RpcCaller.java modified: src/generated/java/com/github/copilot/sdk/generated/rpc/RpcMapper.java modified: src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentApi.java modified: src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsApi.java modified: src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsApi.java modified: src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFleetApi.java modified: src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryApi.java modified: src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpApi.java modified: src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeApi.java modified: src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelApi.java modified: src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsApi.java modified: src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanApi.java modified: src/generated/java/com/github/copilot/sdk/generated/rpc/SessionRpc.java modified: src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellApi.java modified: src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsApi.java modified: src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsApi.java modified: src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiApi.java modified: src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceApi.java - Regenerated. Signed-off-by: Ed Burns --- scripts/codegen/java.ts | 18 ++++++++++++------ .../copilot/sdk/generated/rpc/RpcCaller.java | 5 ++--- .../copilot/sdk/generated/rpc/RpcMapper.java | 2 +- .../sdk/generated/rpc/SessionAgentApi.java | 3 +++ .../sdk/generated/rpc/SessionCommandsApi.java | 3 +++ .../generated/rpc/SessionExtensionsApi.java | 6 ++++++ .../sdk/generated/rpc/SessionFleetApi.java | 3 +++ .../sdk/generated/rpc/SessionHistoryApi.java | 3 +++ .../sdk/generated/rpc/SessionMcpApi.java | 6 ++++++ .../sdk/generated/rpc/SessionModeApi.java | 3 +++ .../sdk/generated/rpc/SessionModelApi.java | 3 +++ .../generated/rpc/SessionPermissionsApi.java | 3 +++ .../sdk/generated/rpc/SessionPlanApi.java | 3 +++ .../copilot/sdk/generated/rpc/SessionRpc.java | 3 +++ .../sdk/generated/rpc/SessionShellApi.java | 6 ++++++ .../sdk/generated/rpc/SessionSkillsApi.java | 6 ++++++ .../sdk/generated/rpc/SessionToolsApi.java | 3 +++ .../sdk/generated/rpc/SessionUiApi.java | 6 ++++++ .../sdk/generated/rpc/SessionWorkspaceApi.java | 6 ++++++ 19 files changed, 81 insertions(+), 10 deletions(-) diff --git a/scripts/codegen/java.ts b/scripts/codegen/java.ts index 84b9e8bf1..375c5f10a 100644 --- a/scripts/codegen/java.ts +++ b/scripts/codegen/java.ts @@ -167,7 +167,8 @@ function schemaTypeToJava( if (schema.type === "array") { const items = schema.items as JSONSchema7 | undefined; if (items) { - const itemResult = schemaTypeToJava(items, true, context, propName + "Item", nestedTypes); + // Always pass required=false so primitives are boxed (List, not List) + const itemResult = schemaTypeToJava(items, false, context, propName + "Item", nestedTypes); imports.add("java.util.List"); for (const imp of itemResult.imports) imports.add(imp); return { javaType: `List<${itemResult.javaType}>`, imports }; @@ -194,7 +195,8 @@ function schemaTypeToJava( const valueSchema = typeof schema.additionalProperties === "object" ? schema.additionalProperties as JSONSchema7 : { type: "object" } as JSONSchema7; - const valueResult = schemaTypeToJava(valueSchema, true, context, propName + "Value", nestedTypes); + // Always pass required=false so primitives are boxed (Map, not Map) + const valueResult = schemaTypeToJava(valueSchema, false, context, propName + "Value", nestedTypes); imports.add("java.util.Map"); for (const imp of valueResult.imports) imports.add(imp); return { javaType: `Map`, imports }; @@ -885,6 +887,11 @@ function generateApiMethod( ?? `Invokes {@code ${method.rpcMethod}}.`; lines.push(` /**`); lines.push(` * ${description}`); + if (isSession && hasExtraParams && hasSessionId) { + lines.push(` *

`); + lines.push(` * Note: the {@code sessionId} field in the params record is overridden`); + lines.push(` * by the session-scoped wrapper; any value provided is ignored.`); + } if (method.stability === "experimental") { lines.push(` *`); lines.push(` * @apiNote This method is experimental and may change in a future version.`); @@ -1199,12 +1206,11 @@ async function generateRpcCallerInterface(packageName: string, packageDir: strin lines.push(` * Interface for invoking JSON-RPC methods with typed responses.`); lines.push(` *

`); lines.push(` * Implementations delegate to the underlying transport layer`); - lines.push(` * (e.g., a {@code JsonRpcClient} instance). Use a method reference:`); + lines.push(` * (e.g., a {@code JsonRpcClient} instance). A method reference is typically the clearest`); + lines.push(` * way to adapt a generic {@code invoke} method to this interface:`); lines.push(` *

{@code`);
     lines.push(` * RpcCaller caller = jsonRpcClient::invoke;`);
     lines.push(` * }
`); - lines.push(` * Note: because the {@code invoke} method has a type parameter, this interface cannot`); - lines.push(` * be implemented using a lambda expression — use a method reference or anonymous class.`); lines.push(` *`); lines.push(` * @since 1.0.0`); lines.push(` */`); @@ -1256,7 +1262,7 @@ async function generateRpcMapperClass(packageName: string, packageDir: string): lines.push(`final class RpcMapper {`); lines.push(``); lines.push(` static final com.fasterxml.jackson.databind.ObjectMapper INSTANCE =`); - lines.push(` new com.fasterxml.jackson.databind.ObjectMapper();`); + lines.push(` com.github.copilot.sdk.JsonRpcClient.getObjectMapper();`); lines.push(``); lines.push(` private RpcMapper() {}`); lines.push(`}`); diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/RpcCaller.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/RpcCaller.java index 8334649bc..d15513ce0 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/rpc/RpcCaller.java +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/RpcCaller.java @@ -14,12 +14,11 @@ * Interface for invoking JSON-RPC methods with typed responses. *

* Implementations delegate to the underlying transport layer - * (e.g., a {@code JsonRpcClient} instance). Use a method reference: + * (e.g., a {@code JsonRpcClient} instance). A method reference is typically the clearest + * way to adapt a generic {@code invoke} method to this interface: *

{@code
  * RpcCaller caller = jsonRpcClient::invoke;
  * }
- * Note: because the {@code invoke} method has a type parameter, this interface cannot - * be implemented using a lambda expression — use a method reference or anonymous class. * * @since 1.0.0 */ diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/RpcMapper.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/RpcMapper.java index 36c1f02fb..24304c227 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/rpc/RpcMapper.java +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/RpcMapper.java @@ -22,7 +22,7 @@ final class RpcMapper { static final com.fasterxml.jackson.databind.ObjectMapper INSTANCE = - new com.fasterxml.jackson.databind.ObjectMapper(); + com.github.copilot.sdk.JsonRpcClient.getObjectMapper(); private RpcMapper() {} } diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentApi.java index 068589915..47192e631 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentApi.java +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentApi.java @@ -51,6 +51,9 @@ public CompletableFuture getCurrent() { /** * Invokes {@code session.agent.select}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsApi.java index 8240ea871..351a2d14c 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsApi.java +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsApi.java @@ -31,6 +31,9 @@ public final class SessionCommandsApi { /** * Invokes {@code session.commands.handlePendingCommand}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * @since 1.0.0 */ public CompletableFuture handlePendingCommand(SessionCommandsHandlePendingCommandParams params) { diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsApi.java index 7c5ef452a..38f8dedf2 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsApi.java +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsApi.java @@ -41,6 +41,9 @@ public CompletableFuture list() { /** * Invokes {@code session.extensions.enable}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -53,6 +56,9 @@ public CompletableFuture enable(SessionExtensionsEnableParams params) { /** * Invokes {@code session.extensions.disable}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFleetApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFleetApi.java index 8eb7558f5..d7aa719a7 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFleetApi.java +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFleetApi.java @@ -31,6 +31,9 @@ public final class SessionFleetApi { /** * Invokes {@code session.fleet.start}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryApi.java index ed0014b71..e1f179e53 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryApi.java +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryApi.java @@ -41,6 +41,9 @@ public CompletableFuture compact() { /** * Invokes {@code session.history.truncate}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpApi.java index a492c1e0c..d6fe3a7eb 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpApi.java +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpApi.java @@ -41,6 +41,9 @@ public CompletableFuture list() { /** * Invokes {@code session.mcp.enable}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -53,6 +56,9 @@ public CompletableFuture enable(SessionMcpEnableParams params) { /** * Invokes {@code session.mcp.disable}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeApi.java index dc04fdb74..7fd8eff73 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeApi.java +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeApi.java @@ -39,6 +39,9 @@ public CompletableFuture get() { /** * Invokes {@code session.mode.set}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * @since 1.0.0 */ public CompletableFuture set(SessionModeSetParams params) { diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelApi.java index c1de6c619..6c8099d0c 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelApi.java +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelApi.java @@ -39,6 +39,9 @@ public CompletableFuture getCurrent() { /** * Invokes {@code session.model.switchTo}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * @since 1.0.0 */ public CompletableFuture switchTo(SessionModelSwitchToParams params) { diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsApi.java index a0faf0414..38c2dd4fc 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsApi.java +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsApi.java @@ -31,6 +31,9 @@ public final class SessionPermissionsApi { /** * Invokes {@code session.permissions.handlePendingPermissionRequest}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * @since 1.0.0 */ public CompletableFuture handlePendingPermissionRequest(SessionPermissionsHandlePendingPermissionRequestParams params) { diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanApi.java index cfd26bd1d..8792bce7e 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanApi.java +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanApi.java @@ -39,6 +39,9 @@ public CompletableFuture read() { /** * Invokes {@code session.plan.update}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * @since 1.0.0 */ public CompletableFuture update(SessionPlanUpdateParams params) { diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionRpc.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionRpc.java index eeef86f54..9faf4612d 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionRpc.java +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionRpc.java @@ -93,6 +93,9 @@ public SessionRpc(RpcCaller caller, String sessionId) { /** * Invokes {@code session.log}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * @since 1.0.0 */ public CompletableFuture log(SessionLogParams params) { diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellApi.java index 2856e213a..b86074342 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellApi.java +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellApi.java @@ -31,6 +31,9 @@ public final class SessionShellApi { /** * Invokes {@code session.shell.exec}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * @since 1.0.0 */ public CompletableFuture exec(SessionShellExecParams params) { @@ -41,6 +44,9 @@ public CompletableFuture exec(SessionShellExecParams par /** * Invokes {@code session.shell.kill}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * @since 1.0.0 */ public CompletableFuture kill(SessionShellKillParams params) { diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsApi.java index 6189d703a..b32419a3e 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsApi.java +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsApi.java @@ -41,6 +41,9 @@ public CompletableFuture list() { /** * Invokes {@code session.skills.enable}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -53,6 +56,9 @@ public CompletableFuture enable(SessionSkillsEnableParams params) { /** * Invokes {@code session.skills.disable}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsApi.java index 513281198..91d0587c7 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsApi.java +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsApi.java @@ -31,6 +31,9 @@ public final class SessionToolsApi { /** * Invokes {@code session.tools.handlePendingToolCall}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * @since 1.0.0 */ public CompletableFuture handlePendingToolCall(SessionToolsHandlePendingToolCallParams params) { diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiApi.java index b5eaf872e..a987bd627 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiApi.java +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiApi.java @@ -31,6 +31,9 @@ public final class SessionUiApi { /** * Invokes {@code session.ui.elicitation}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * @since 1.0.0 */ public CompletableFuture elicitation(SessionUiElicitationParams params) { @@ -41,6 +44,9 @@ public CompletableFuture elicitation(SessionUiElicit /** * Invokes {@code session.ui.handlePendingElicitation}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * @since 1.0.0 */ public CompletableFuture handlePendingElicitation(SessionUiHandlePendingElicitationParams params) { diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceApi.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceApi.java index ce6e35192..8fd7d7467 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceApi.java +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceApi.java @@ -39,6 +39,9 @@ public CompletableFuture listFiles() { /** * Invokes {@code session.workspace.readFile}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * @since 1.0.0 */ public CompletableFuture readFile(SessionWorkspaceReadFileParams params) { @@ -49,6 +52,9 @@ public CompletableFuture readFile(SessionWorkspa /** * Invokes {@code session.workspace.createFile}. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. * @since 1.0.0 */ public CompletableFuture createFile(SessionWorkspaceCreateFileParams params) { From e3598b5e68eff22b21a831077fd0a9691923274d Mon Sep 17 00:00:00 2001 From: Ed Burns Date: Fri, 17 Apr 2026 19:11:39 -0400 Subject: [PATCH 80/80] Fix compilation failure. modified: scripts/codegen/java.ts modified: src/generated/java/com/github/copilot/sdk/generated/rpc/RpcMapper.java Clean run. The fix was: RpcMapper now constructs its own ObjectMapper with the same configuration as JsonRpcClient's mapper, instead of trying to call JsonRpcClient.getObjectMapper() across packages (which failed because JsonRpcClient is package-private). Signed-off-by: Ed Burns --- scripts/codegen/java.ts | 14 ++++++++++++-- .../copilot/sdk/generated/rpc/RpcMapper.java | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/scripts/codegen/java.ts b/scripts/codegen/java.ts index 375c5f10a..7c2ea7091 100644 --- a/scripts/codegen/java.ts +++ b/scripts/codegen/java.ts @@ -1255,14 +1255,24 @@ async function generateRpcMapperClass(packageName: string, packageDir: string): lines.push(` *

`); lines.push(` * {@link com.fasterxml.jackson.databind.ObjectMapper} is thread-safe and expensive to`); lines.push(` * instantiate, so a single shared instance is used across all generated API classes.`); + lines.push(` * The configuration mirrors {@code JsonRpcClient}'s mapper (JavaTimeModule, lenient`); + lines.push(` * unknown-property handling, ISO date format, NON_NULL inclusion).`); lines.push(` *`); lines.push(` * @since 1.0.0`); lines.push(` */`); lines.push(GENERATED_ANNOTATION); lines.push(`final class RpcMapper {`); lines.push(``); - lines.push(` static final com.fasterxml.jackson.databind.ObjectMapper INSTANCE =`); - lines.push(` com.github.copilot.sdk.JsonRpcClient.getObjectMapper();`); + lines.push(` static final com.fasterxml.jackson.databind.ObjectMapper INSTANCE = createMapper();`); + lines.push(``); + lines.push(` private static com.fasterxml.jackson.databind.ObjectMapper createMapper() {`); + lines.push(` com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();`); + lines.push(` mapper.registerModule(new com.fasterxml.jackson.datatype.jsr310.JavaTimeModule());`); + lines.push(` mapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);`); + lines.push(` mapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);`); + lines.push(` mapper.setDefaultPropertyInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL);`); + lines.push(` return mapper;`); + lines.push(` }`); lines.push(``); lines.push(` private RpcMapper() {}`); lines.push(`}`); diff --git a/src/generated/java/com/github/copilot/sdk/generated/rpc/RpcMapper.java b/src/generated/java/com/github/copilot/sdk/generated/rpc/RpcMapper.java index 24304c227..87d432820 100644 --- a/src/generated/java/com/github/copilot/sdk/generated/rpc/RpcMapper.java +++ b/src/generated/java/com/github/copilot/sdk/generated/rpc/RpcMapper.java @@ -15,14 +15,24 @@ *

* {@link com.fasterxml.jackson.databind.ObjectMapper} is thread-safe and expensive to * instantiate, so a single shared instance is used across all generated API classes. + * The configuration mirrors {@code JsonRpcClient}'s mapper (JavaTimeModule, lenient + * unknown-property handling, ISO date format, NON_NULL inclusion). * * @since 1.0.0 */ @javax.annotation.processing.Generated("copilot-sdk-codegen") final class RpcMapper { - static final com.fasterxml.jackson.databind.ObjectMapper INSTANCE = - com.github.copilot.sdk.JsonRpcClient.getObjectMapper(); + static final com.fasterxml.jackson.databind.ObjectMapper INSTANCE = createMapper(); + + private static com.fasterxml.jackson.databind.ObjectMapper createMapper() { + com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper(); + mapper.registerModule(new com.fasterxml.jackson.datatype.jsr310.JavaTimeModule()); + mapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + mapper.setDefaultPropertyInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL); + return mapper; + } private RpcMapper() {} }