From c9f79c955fc99f29ce7b599eb4b170f9daacf45b Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Mon, 6 Apr 2026 13:33:03 -0400 Subject: [PATCH 01/13] docs: add Java language tabs across all SDK documentation Add Java code examples to all 22 language-tabbed documentation files, matching the existing Node.js, Python, Go, and .NET tabs. Files updated: - docs/getting-started.md (8 sections + telemetry table + text refs) - docs/features/ (7 files: index, hooks, custom-agents, image-input, streaming-events, steering-and-queueing, skills) - docs/hooks/ (6 files: index, pre-tool-use, post-tool-use, user-prompt-submitted, session-lifecycle, error-handling) - docs/auth/ (2 files: index, byok) - docs/setup/ (4 files: local-cli, bundled-cli, backend-services, github-oauth) - docs/observability/opentelemetry.md - docs/troubleshooting/debugging.md - docs/integrations/microsoft-agent-framework.md All Java examples use idiomatic patterns: CompletableFuture, try-with-resources, ToolDefinition.create(), PermissionHandler.APPROVE_ALL, typed event handlers, and builder-style configuration. --- docs/auth/byok.md | 52 +++ docs/auth/index.md | 44 +++ docs/features/custom-agents.md | 87 +++++ docs/features/hooks.md | 53 +++ docs/features/image-input.md | 56 +++ docs/features/index.md | 2 +- docs/features/skills.md | 42 +++ docs/features/steering-and-queueing.md | 65 ++++ docs/features/streaming-events.md | 15 + docs/getting-started.md | 347 +++++++++++++++++- docs/hooks/error-handling.md | 40 ++ docs/hooks/index.md | 33 ++ docs/hooks/post-tool-use.md | 39 ++ docs/hooks/pre-tool-use.md | 38 ++ docs/hooks/session-lifecycle.md | 28 ++ docs/hooks/user-prompt-submitted.md | 37 ++ .../integrations/microsoft-agent-framework.md | 189 +++++++++- docs/observability/opentelemetry.md | 32 +- docs/setup/backend-services.md | 25 ++ docs/setup/bundled-cli.md | 29 ++ docs/setup/github-oauth.md | 32 ++ docs/setup/local-cli.md | 23 ++ docs/troubleshooting/debugging.md | 45 +++ 23 files changed, 1335 insertions(+), 18 deletions(-) diff --git a/docs/auth/byok.md b/docs/auth/byok.md index a4a131913b..6965404a16 100644 --- a/docs/auth/byok.md +++ b/docs/auth/byok.md @@ -164,6 +164,37 @@ Console.WriteLine(response?.Data.Content); +
+Java + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.CopilotClientOptions; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; + +var client = new CopilotClient(); +client.start().get(); + +var session = client.createSession(new SessionConfig() + .setModel("gpt-5.2-codex") // Your deployment name + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setProvider(new ProviderConfig() + .setType("openai") + .setBaseUrl("https://your-resource.openai.azure.com/openai/v1/") + .setWireApi("responses") // Use "completions" for older models + .setApiKey(System.getenv("FOUNDRY_API_KEY"))) +).get(); + +var response = session.sendAndWait(new MessageOptions() + .setPrompt("What is 2+2?")).get(); +System.out.println(response.getData().getContent()); + +client.stop().get(); +``` + +
+ ## Provider Configuration Reference ### ProviderConfig Fields @@ -412,6 +443,27 @@ var client = new CopilotClient(new CopilotClientOptions +
+Java + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.CopilotClientOptions; + +var client = new CopilotClient(new CopilotClientOptions() + .setOnListModels(() -> List.of( + new ModelInfo() + .setId("my-custom-model") + .setName("My Custom Model") + .setCapabilities(new ModelCapabilities() + .setSupports(new ModelSupports().setVision(false).setReasoningEffort(false)) + .setLimits(new ModelLimits().setMaxContextWindowTokens(128000))) + )) +); +``` + +
+ Results are cached after the first call, just like the default behavior. The handler completely replaces the CLI's `models.list` RPC — no fallback to the server occurs. ## Limitations diff --git a/docs/auth/index.md b/docs/auth/index.md index 2f36d8b21d..f06af961eb 100644 --- a/docs/auth/index.md +++ b/docs/auth/index.md @@ -85,6 +85,19 @@ await using var client = new CopilotClient(); +
+Java + +```java +import com.github.copilot.sdk.CopilotClient; + +// Default: uses logged-in user credentials +var client = new CopilotClient(); +client.start().get(); +``` + +
+ **When to use:** - Desktop applications where users interact directly - Development and testing environments @@ -189,6 +202,22 @@ await using var client = new CopilotClient(new CopilotClientOptions +
+Java + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.CopilotClientOptions; + +var client = new CopilotClient(new CopilotClientOptions() + .setGitHubToken(userAccessToken) // Token from OAuth flow + .setUseLoggedInUser(false) // Don't use stored CLI credentials +); +client.start().get(); +``` + +
+ **Supported token types:** - `gho_` - OAuth user access tokens - `ghu_` - GitHub App user access tokens @@ -351,6 +380,21 @@ await using var client = new CopilotClient(new CopilotClientOptions +
+Java + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.CopilotClientOptions; + +var client = new CopilotClient(new CopilotClientOptions() + .setUseLoggedInUser(false) // Only use explicit tokens +); +client.start().get(); +``` + +
+ ## Next Steps - [BYOK Documentation](./byok.md) - Learn how to use your own API keys diff --git a/docs/features/custom-agents.md b/docs/features/custom-agents.md index c1d01ba322..6fae2fd193 100644 --- a/docs/features/custom-agents.md +++ b/docs/features/custom-agents.md @@ -205,6 +205,39 @@ await using var session = await client.CreateSessionAsync(new SessionConfig +
+Java + +```java +import com.github.copilot.sdk.CopilotClient; + +try (var client = new CopilotClient()) { + client.start().get(); + + var session = client.createSession( + new SessionConfig() + .setModel("gpt-4.1") + .setCustomAgents(List.of( + new CustomAgentConfig() + .setName("researcher") + .setDisplayName("Research Agent") + .setDescription("Explores codebases and answers questions using read-only tools") + .setTools(List.of("grep", "glob", "view")) + .setPrompt("You are a research assistant. Analyze code and answer questions. Do not modify any files."), + new CustomAgentConfig() + .setName("editor") + .setDisplayName("Editor Agent") + .setDescription("Makes targeted code changes") + .setTools(List.of("view", "edit", "bash")) + .setPrompt("You are a code editor. Make minimal, surgical changes to files as requested.") + )) + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + ).get(); +} +``` + +
+ ## Configuration Reference | Property | Type | Required | Description | @@ -316,6 +349,28 @@ var session = await client.CreateSessionAsync(new SessionConfig +
+Java + + +```java +var session = client.createSession( + new SessionConfig() + .setCustomAgents(List.of( + new CustomAgentConfig() + .setName("researcher") + .setPrompt("You are a research assistant. Analyze code and answer questions."), + new CustomAgentConfig() + .setName("editor") + .setPrompt("You are a code editor. Make minimal, surgical changes.") + )) + .setAgent("researcher") // Pre-select the researcher agent + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) +).get(); +``` + +
+ ## How Sub-Agent Delegation Works When you send a prompt to a session with custom agents, the runtime evaluates whether to delegate to a sub-agent: @@ -561,6 +616,38 @@ await session.SendAndWaitAsync(new MessageOptions +
+Java + +```java +session.on(event -> { + switch (event.getType()) { + case "subagent.started" -> { + System.out.println("▶ Sub-agent started: " + event.getData().agentDisplayName()); + System.out.println(" Description: " + event.getData().agentDescription()); + System.out.println(" Tool call ID: " + event.getData().toolCallId()); + } + case "subagent.completed" -> + System.out.println("✅ Sub-agent completed: " + event.getData().agentDisplayName()); + case "subagent.failed" -> { + System.out.println("❌ Sub-agent failed: " + event.getData().agentDisplayName()); + System.out.println(" Error: " + event.getData().error()); + } + case "subagent.selected" -> + System.out.println("🎯 Agent selected: " + event.getData().agentDisplayName()); + case "subagent.deselected" -> + System.out.println("↩ Agent deselected, returning to parent"); + default -> {} + } +}); + +var response = session.sendAndWait( + new MessageOptions().setPrompt("Research how authentication works in this codebase") +).get(); +``` + +
+ ## Building an Agent Tree UI Sub-agent events include `toolCallId` fields that let you reconstruct the execution tree. Here's a pattern for tracking agent activity: diff --git a/docs/features/hooks.md b/docs/features/hooks.md index 1a01c5f1a4..840638f5b2 100644 --- a/docs/features/hooks.md +++ b/docs/features/hooks.md @@ -195,6 +195,31 @@ var session = await client.CreateSessionAsync(new SessionConfig +
+Java + +```java +import com.github.copilot.sdk.CopilotClient; + +try (var client = new CopilotClient()) { + client.start().get(); + + var hooks = new SessionHooks() + .setOnSessionStart((input, inv) -> CompletableFuture.completedFuture(null)) + .setOnPreToolUse((input, inv) -> CompletableFuture.completedFuture(null)) + .setOnPostToolUse((input, inv) -> CompletableFuture.completedFuture(null)); + // ... add only the hooks you need + + var session = client.createSession( + new SessionConfig() + .setHooks(hooks) + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + ).get(); +} +``` + +
+ > **Tip:** Every hook handler receives an `invocation` parameter containing the `sessionId`, which is useful for correlating logs and maintaining per-session state. --- @@ -380,6 +405,34 @@ var session = await client.CreateSessionAsync(new SessionConfig +
+Java + +```java +var readOnlyTools = Set.of("read_file", "glob", "grep", "view"); + +var hooks = new SessionHooks() + .setOnPreToolUse((input, invocation) -> { + if (!readOnlyTools.contains(input.toolName())) { + return CompletableFuture.completedFuture( + new PreToolUseHookOutput() + .setPermissionDecision("deny") + .setPermissionDecisionReason( + "Only read-only tools are allowed. \"" + input.toolName() + "\" was blocked.") + ); + } + return CompletableFuture.completedFuture(PreToolUseHookOutput.allow()); + }); + +var session = client.createSession( + new SessionConfig() + .setHooks(hooks) + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) +).get(); +``` + +
+ ### Restrict file access to specific directories ```typescript diff --git a/docs/features/image-input.md b/docs/features/image-input.md index 047dc62806..33a55c849b 100644 --- a/docs/features/image-input.md +++ b/docs/features/image-input.md @@ -219,6 +219,32 @@ await session.SendAsync(new MessageOptions +
+Java + +```java +import com.github.copilot.sdk.CopilotClient; + +try (var client = new CopilotClient()) { + client.start().get(); + + var session = client.createSession( + new SessionConfig() + .setModel("gpt-4.1") + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + ).get(); + + session.send(new MessageOptions() + .setPrompt("Describe what you see in this image") + .setAttachments(List.of( + new Attachment("file", "/absolute/path/to/screenshot.png", "screenshot.png") + )) + ).get(); +} +``` + +
+ ## Quick Start — Blob Attachment When you already have image data in memory (e.g., a screenshot captured by your app, or an image fetched from an API), use a blob attachment to send it directly without writing to disk. @@ -400,6 +426,36 @@ await session.SendAsync(new MessageOptions +
+Java + +```java +import com.github.copilot.sdk.CopilotClient; + +try (var client = new CopilotClient()) { + client.start().get(); + + var session = client.createSession( + new SessionConfig() + .setModel("gpt-4.1") + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + ).get(); + + var base64ImageData = "..."; // your base64-encoded image + session.send(new MessageOptions() + .setPrompt("Describe what you see in this image") + .setAttachments(List.of( + new BlobAttachment() + .setData(base64ImageData) + .setMimeType("image/png") + .setDisplayName("screenshot.png") + )) + ).get(); +} +``` + +
+ ## Supported Formats Supported image formats include JPG, PNG, GIF, and other common image types. For file attachments, the runtime reads the image from disk and converts it as needed. For blob attachments, you provide the base64 data and MIME type directly. Use PNG or JPEG for best results, as these are the most widely supported formats. diff --git a/docs/features/index.md b/docs/features/index.md index 02fabe5ab9..bbd005cb09 100644 --- a/docs/features/index.md +++ b/docs/features/index.md @@ -1,6 +1,6 @@ # Features -These guides cover the capabilities you can add to your Copilot SDK application. Each guide includes examples in all supported languages (TypeScript, Python, Go, and .NET). +These guides cover the capabilities you can add to your Copilot SDK application. Each guide includes examples in all supported languages (TypeScript, Python, Go, .NET, and Java). > **New to the SDK?** Start with the [Getting Started tutorial](../getting-started.md) first, then come back here to add more capabilities. diff --git a/docs/features/skills.md b/docs/features/skills.md index 3bc9294aa1..683da5a405 100644 --- a/docs/features/skills.md +++ b/docs/features/skills.md @@ -140,6 +140,34 @@ await session.SendAndWaitAsync(new MessageOptions +
+Java + +```java +import com.github.copilot.sdk.CopilotClient; + +try (var client = new CopilotClient()) { + client.start().get(); + + var session = client.createSession( + new SessionConfig() + .setModel("gpt-4.1") + .setSkillDirectories(List.of( + "./skills/code-review", + "./skills/documentation" + )) + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + ).get(); + + // Copilot now has access to skills in those directories + session.sendAndWait(new MessageOptions() + .setPrompt("Review this code for security issues") + ).get(); +} +``` + +
+ ## Disabling Skills Disable specific skills while keeping others active: @@ -243,6 +271,20 @@ var session = await client.CreateSessionAsync(new SessionConfig +
+Java + +```java +var session = client.createSession( + new SessionConfig() + .setSkillDirectories(List.of("./skills")) + .setDisabledSkills(List.of("experimental-feature", "deprecated-tool")) + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) +).get(); +``` + +
+ ## Skill Directory Structure Each skill is a named subdirectory containing a `SKILL.md` file: diff --git a/docs/features/steering-and-queueing.md b/docs/features/steering-and-queueing.md index a3e1b6d2b1..c3f1e98576 100644 --- a/docs/features/steering-and-queueing.md +++ b/docs/features/steering-and-queueing.md @@ -178,6 +178,36 @@ await session.SendAsync(new MessageOptions +
+Java + +```java +import com.github.copilot.sdk.CopilotClient; + +try (var client = new CopilotClient()) { + client.start().get(); + + var session = client.createSession( + new SessionConfig() + .setModel("gpt-4.1") + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + ).get(); + + // Start a long-running task + session.send(new MessageOptions() + .setPrompt("Refactor the authentication module to use sessions") + ).get(); + + // While the agent is working, steer it + session.send(new MessageOptions() + .setPrompt("Actually, use JWT tokens instead of sessions") + .setMode("immediate") + ).get(); +} +``` + +
+ ### How Steering Works Internally 1. The message is added to the runtime's `ImmediatePromptProcessor` queue @@ -388,6 +418,41 @@ await session.SendAsync(new MessageOptions +
+Java + +```java +import com.github.copilot.sdk.CopilotClient; + +try (var client = new CopilotClient()) { + client.start().get(); + + var session = client.createSession( + new SessionConfig() + .setModel("gpt-4.1") + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + ).get(); + + // Send an initial task + session.send(new MessageOptions().setPrompt("Set up the project structure")).get(); + + // Queue follow-up tasks while the agent is busy + session.send(new MessageOptions() + .setPrompt("Add unit tests for the auth module") + .setMode("enqueue") + ).get(); + + session.send(new MessageOptions() + .setPrompt("Update the README with setup instructions") + .setMode("enqueue") + ).get(); + + // Messages are processed in FIFO order after each turn completes +} +``` + +
+ ### How Queueing Works Internally 1. The message is added to the session's `itemQueue` as a `QueuedItem` diff --git a/docs/features/streaming-events.md b/docs/features/streaming-events.md index d03ed95fa7..cb069ff70b 100644 --- a/docs/features/streaming-events.md +++ b/docs/features/streaming-events.md @@ -191,6 +191,21 @@ session.On(evt => +
+Java + +```java +// All events +session.on(event -> System.out.println(event.getType() + " " + event.getData())); + +// Specific event type — data is narrowed to the matching class +session.on(AssistantMessageDeltaEvent.class, event -> + System.out.print(event.getData().deltaContent()) +); +``` + +
+ > **Tip (Python / Go):** These SDKs use a single `Data` class/struct with all possible fields as optional/nullable. Only the fields listed in the tables below are populated for each event type — the rest will be `None` / `nil`. > > **Tip (.NET):** The .NET SDK uses separate, strongly-typed data classes per event (e.g., `AssistantMessageDeltaData`), so only the relevant fields exist on each type. diff --git a/docs/getting-started.md b/docs/getting-started.md index e0dc9e1cea..ceb87e90a9 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -20,7 +20,7 @@ Before you begin, make sure you have: - **GitHub Copilot CLI** installed and authenticated ([Installation guide](https://docs.github.com/en/copilot/how-tos/set-up/install-copilot-cli)) - Your preferred language runtime: - - **Node.js** 18+ or **Python** 3.8+ or **Go** 1.21+ or **.NET** 8.0+ + - **Node.js** 18+ or **Python** 3.8+ or **Go** 1.21+ or **Java** 17+ or **.NET** 8.0+ Verify the CLI is working: @@ -92,6 +92,29 @@ dotnet add package GitHub.Copilot.SDK +
+Java + +First, create a new directory and initialize your project. + +**Maven** — add to your `pom.xml`: + +```xml + + com.github.copilot + copilot-sdk + LATEST + +``` + +**Gradle** — add to your `build.gradle`: + +```groovy +implementation 'com.github.copilot:copilot-sdk:LATEST' +``` + +
+ ## Step 2: Send Your First Message Create a new file and add the following code. This is the simplest way to use the SDK—about 5 lines of code. @@ -228,6 +251,45 @@ dotnet run +
+Java + +Create `HelloCopilot.java`: + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; + +public class HelloCopilot { + public static void main(String[] args) throws Exception { + try (var client = new CopilotClient()) { + client.start().get(); + + var session = client.createSession( + new SessionConfig().setModel("gpt-4.1") + ).get(); + + var response = session.sendAndWait( + new MessageOptions().setPrompt("What is 2 + 2?") + ).get(); + + System.out.println(response.getData().content()); + + client.stop().get(); + } + } +} +``` + +Run it: + +```bash +javac -cp copilot-sdk.jar HelloCopilot.java && java -cp .:copilot-sdk.jar HelloCopilot +``` + +
+ **You should see:** ``` @@ -394,6 +456,47 @@ await session.SendAndWaitAsync(new MessageOptions { Prompt = "Tell me a short jo +
+Java + +Update `HelloCopilot.java`: + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; + +public class HelloCopilot { + public static void main(String[] args) throws Exception { + try (var client = new CopilotClient()) { + client.start().get(); + + var session = client.createSession( + new SessionConfig() + .setModel("gpt-4.1") + .setStreaming(true) + ).get(); + + // Listen for response chunks + session.on(AssistantMessageDeltaEvent.class, delta -> { + System.out.print(delta.getData().deltaContent()); + }); + session.on(SessionIdleEvent.class, idle -> { + System.out.println(); // New line when done + }); + + session.sendAndWait( + new MessageOptions().setPrompt("Tell me a short joke") + ).get(); + + client.stop().get(); + } + } +} +``` + +
+ Run the code again. You'll see the response appear word by word. ### Event Subscription Methods @@ -591,6 +694,30 @@ unsubscribe.Dispose(); +
+Java + +```java +// Subscribe to all events +var unsubscribe = session.on(event -> { + System.out.println("Event: " + event.getType()); +}); + +// Subscribe to a specific event type +session.on(AssistantMessageEvent.class, msg -> { + System.out.println("Message: " + msg.getData().content()); +}); + +session.on(SessionIdleEvent.class, idle -> { + System.out.println("Session is idle"); +}); + +// Later, to unsubscribe: +unsubscribe.close(); +``` + +
+ ## Step 4: Add a Custom Tool Now for the powerful part. Let's give Copilot the ability to call your code by defining a custom tool. We'll create a simple weather lookup tool. @@ -841,6 +968,78 @@ await session.SendAndWaitAsync(new MessageOptions +
+Java + +Update `HelloCopilot.java`: + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; + +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.CompletableFuture; + +public class HelloCopilot { + public static void main(String[] args) throws Exception { + var random = new Random(); + var conditions = List.of("sunny", "cloudy", "rainy", "partly cloudy"); + + // Define a tool that Copilot can call + var getWeather = ToolDefinition.create( + "get_weather", + "Get the current weather for a city", + Map.of( + "type", "object", + "properties", Map.of( + "city", Map.of("type", "string", "description", "The city name") + ), + "required", List.of("city") + ), + invocation -> { + var city = (String) invocation.getArguments().get("city"); + var temp = random.nextInt(30) + 50; + var condition = conditions.get(random.nextInt(conditions.size())); + return CompletableFuture.completedFuture(Map.of( + "city", city, + "temperature", temp + "°F", + "condition", condition + )); + } + ); + + try (var client = new CopilotClient()) { + client.start().get(); + + var session = client.createSession( + new SessionConfig() + .setModel("gpt-4.1") + .setStreaming(true) + .setTools(List.of(getWeather)) + ).get(); + + session.on(AssistantMessageDeltaEvent.class, delta -> { + System.out.print(delta.getData().deltaContent()); + }); + session.on(SessionIdleEvent.class, idle -> { + System.out.println(); + }); + + session.sendAndWait( + new MessageOptions().setPrompt("What's the weather like in Seattle and Tokyo?") + ).get(); + + client.stop().get(); + } + } +} +``` + +
+ Run it and you'll see Copilot call your tool to get weather data, then respond with the results! ## Step 5: Build an Interactive Assistant @@ -1165,6 +1364,97 @@ dotnet run +
+Java + +Create `WeatherAssistant.java`: + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; + +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Scanner; +import java.util.concurrent.CompletableFuture; + +public class WeatherAssistant { + public static void main(String[] args) throws Exception { + var random = new Random(); + var conditions = List.of("sunny", "cloudy", "rainy", "partly cloudy"); + + var getWeather = ToolDefinition.create( + "get_weather", + "Get the current weather for a city", + Map.of( + "type", "object", + "properties", Map.of( + "city", Map.of("type", "string", "description", "The city name") + ), + "required", List.of("city") + ), + invocation -> { + var city = (String) invocation.getArguments().get("city"); + var temp = random.nextInt(30) + 50; + var condition = conditions.get(random.nextInt(conditions.size())); + return CompletableFuture.completedFuture(Map.of( + "city", city, + "temperature", temp + "°F", + "condition", condition + )); + } + ); + + try (var client = new CopilotClient()) { + client.start().get(); + + var session = client.createSession( + new SessionConfig() + .setModel("gpt-4.1") + .setStreaming(true) + .setTools(List.of(getWeather)) + ).get(); + + session.on(AssistantMessageDeltaEvent.class, delta -> { + System.out.print(delta.getData().deltaContent()); + }); + session.on(SessionIdleEvent.class, idle -> { + System.out.println(); + }); + + System.out.println("🌤️ Weather Assistant (type 'exit' to quit)"); + System.out.println(" Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA'\n"); + + var scanner = new Scanner(System.in); + while (true) { + System.out.print("You: "); + if (!scanner.hasNextLine()) break; + var input = scanner.nextLine(); + if (input.equalsIgnoreCase("exit")) break; + + System.out.print("Assistant: "); + session.sendAndWait( + new MessageOptions().setPrompt(input) + ).get(); + System.out.println("\n"); + } + + client.stop().get(); + } + } +} +``` + +Run with: + +```bash +javac -cp copilot-sdk.jar WeatherAssistant.java && java -cp .:copilot-sdk.jar WeatherAssistant +``` + +
+ **Example session:** @@ -1273,7 +1563,7 @@ Available section IDs: `identity`, `tone`, `tool_efficiency`, `environment_conte Each override supports four actions: `replace`, `remove`, `append`, and `prepend`. Unknown section IDs are handled gracefully — content is appended to additional instructions and a warning is emitted; `remove` on unknown sections is silently ignored. -See the language-specific SDK READMEs for examples in [TypeScript](../nodejs/README.md), [Python](../python/README.md), [Go](../go/README.md), and [C#](../dotnet/README.md). +See the language-specific SDK READMEs for examples in [TypeScript](../nodejs/README.md), [Python](../python/README.md), [Go](../go/README.md), [Java](../java/README.md), and [C#](../dotnet/README.md). --- @@ -1412,6 +1702,27 @@ await using var session = await client.CreateSessionAsync(new() +
+Java + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.CopilotClientOptions; + +var client = new CopilotClient( + new CopilotClientOptions().setCliUrl("localhost:4321") +); +client.start().get(); + +// Use the client normally +var session = client.createSession( + new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL) +).get(); +// ... +``` + +
+ **Note:** When `cli_url` / `cliUrl` / `CLIUrl` is provided, the SDK will not spawn or manage a CLI process - it will only connect to the existing server at the specified URL. --- @@ -1494,15 +1805,32 @@ No extra dependencies — uses built-in `System.Diagnostics.Activity`. +
+Java + + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.CopilotClientOptions; + +var client = new CopilotClient(new CopilotClientOptions() + .setTelemetry(new TelemetryConfig() + .setOtlpEndpoint("http://localhost:4318"))); +``` + +Dependency: `io.opentelemetry:opentelemetry-api` + +
+ ### TelemetryConfig Options -| Option | Node.js | Python | Go | .NET | Description | -|---|---|---|---|---|---| -| OTLP endpoint | `otlpEndpoint` | `otlp_endpoint` | `OTLPEndpoint` | `OtlpEndpoint` | OTLP HTTP endpoint URL | -| File path | `filePath` | `file_path` | `FilePath` | `FilePath` | File path for JSON-lines trace output | -| Exporter type | `exporterType` | `exporter_type` | `ExporterType` | `ExporterType` | `"otlp-http"` or `"file"` | -| Source name | `sourceName` | `source_name` | `SourceName` | `SourceName` | Instrumentation scope name | -| Capture content | `captureContent` | `capture_content` | `CaptureContent` | `CaptureContent` | Whether to capture message content | +| Option | Node.js | Python | Go | Java | .NET | Description | +|---|---|---|---|---|---|---| +| OTLP endpoint | `otlpEndpoint` | `otlp_endpoint` | `OTLPEndpoint` | `otlpEndpoint` | `OtlpEndpoint` | OTLP HTTP endpoint URL | +| File path | `filePath` | `file_path` | `FilePath` | `filePath` | `FilePath` | File path for JSON-lines trace output | +| Exporter type | `exporterType` | `exporter_type` | `ExporterType` | `exporterType` | `ExporterType` | `"otlp-http"` or `"file"` | +| Source name | `sourceName` | `source_name` | `SourceName` | `sourceName` | `SourceName` | Instrumentation scope name | +| Capture content | `captureContent` | `capture_content` | `CaptureContent` | `captureContent` | `CaptureContent` | Whether to capture message content | ### File Export @@ -1537,6 +1865,7 @@ Trace context is propagated automatically — no manual instrumentation is neede - [Python SDK Reference](../python/README.md) - [Go SDK Reference](../go/README.md) - [.NET SDK Reference](../dotnet/README.md) +- [Java SDK Reference](../java/README.md) - [Using MCP Servers](./features/mcp.md) - Integrate external tools via Model Context Protocol - [GitHub MCP Server Documentation](https://github.com/github/github-mcp-server) - [MCP Servers Directory](https://github.com/modelcontextprotocol/servers) - Explore more MCP servers diff --git a/docs/hooks/error-handling.md b/docs/hooks/error-handling.md index b575db0ce8..ed97d6202d 100644 --- a/docs/hooks/error-handling.md +++ b/docs/hooks/error-handling.md @@ -99,6 +99,22 @@ public delegate Task ErrorOccurredHandler( +
+Java + +```java +// Note: Java SDK does not have an onErrorOccurred hook. +// Use EventErrorPolicy and EventErrorHandler instead: +import com.github.copilot.sdk.*; + +session.setEventErrorPolicy(EventErrorPolicy.SUPPRESS_AND_LOG_ERRORS); +session.setEventErrorHandler((event, ex) -> { + System.err.println("Error in " + event.getType() + ": " + ex.getMessage()); +}); +``` + +
+ ## Input | Field | Type | Description | @@ -251,6 +267,30 @@ var session = await client.CreateSessionAsync(new SessionConfig +
+Java + +```java +import com.github.copilot.sdk.*; +import com.github.copilot.sdk.json.*; + +// Note: Java SDK does not have an onErrorOccurred hook. +// Use EventErrorPolicy and EventErrorHandler instead: + +var session = client.createSession( + new SessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) +).get(); + +session.setEventErrorPolicy(EventErrorPolicy.SUPPRESS_AND_LOG_ERRORS); +session.setEventErrorHandler((event, ex) -> { + System.err.println("[" + session.getId() + "] Error: " + ex.getMessage()); + System.err.println(" Event: " + event.getType()); +}); +``` + +
+ ### Send Errors to Monitoring Service ```typescript diff --git a/docs/hooks/index.md b/docs/hooks/index.md index f0bf9af3c5..3d1c11e151 100644 --- a/docs/hooks/index.md +++ b/docs/hooks/index.md @@ -156,6 +156,39 @@ var session = await client.CreateSessionAsync(new SessionConfig +
+Java + +```java +import com.github.copilot.sdk.*; +import com.github.copilot.sdk.json.*; +import java.util.concurrent.CompletableFuture; + +var client = new CopilotClient(); + +var hooks = new SessionHooks() + .setOnPreToolUse((input, invocation) -> { + System.out.println("Tool called: " + input.getToolName()); + return CompletableFuture.completedFuture(PreToolUseHookOutput.allow()); + }) + .setOnPostToolUse((input, invocation) -> { + System.out.println("Tool result: " + input.getToolResult()); + return CompletableFuture.completedFuture(null); + }) + .setOnSessionStart((input, invocation) -> { + return CompletableFuture.completedFuture( + new SessionStartHookOutput().setAdditionalContext("User prefers concise answers.") + ); + }); + +var session = client.createSession( + new SessionConfig() + .setHooks(hooks) +).get(); +``` + +
+ ## Hook Invocation Context Every hook receives an `invocation` parameter with context about the current session: diff --git a/docs/hooks/post-tool-use.md b/docs/hooks/post-tool-use.md index d0b5f789aa..e3ff11a28a 100644 --- a/docs/hooks/post-tool-use.md +++ b/docs/hooks/post-tool-use.md @@ -99,6 +99,20 @@ public delegate Task PostToolUseHandler( +
+Java + +```java +import com.github.copilot.sdk.json.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiFunction; + +BiFunction> postToolUseHandler; +``` + +
+ ## Input | Field | Type | Description | @@ -250,6 +264,31 @@ var session = await client.CreateSessionAsync(new SessionConfig +
+Java + +```java +import com.github.copilot.sdk.*; +import com.github.copilot.sdk.json.*; +import java.util.concurrent.CompletableFuture; + +var hooks = new SessionHooks() + .setOnPostToolUse((input, invocation) -> { + System.out.println("[" + invocation.getSessionId() + "] Tool: " + input.getToolName()); + System.out.println(" Args: " + input.getToolArgs()); + System.out.println(" Result: " + input.getToolResult()); + return CompletableFuture.completedFuture(null); + }); + +var session = client.createSession( + new SessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setHooks(hooks) +).get(); +``` + +
+ ### Redact Sensitive Data ```typescript diff --git a/docs/hooks/pre-tool-use.md b/docs/hooks/pre-tool-use.md index c87b32be0f..286bb1cfb8 100644 --- a/docs/hooks/pre-tool-use.md +++ b/docs/hooks/pre-tool-use.md @@ -99,6 +99,20 @@ public delegate Task PreToolUseHandler( +
+Java + +```java +import com.github.copilot.sdk.json.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiFunction; + +BiFunction> preToolUseHandler; +``` + +
+ ## Input | Field | Type | Description | @@ -261,6 +275,30 @@ var session = await client.CreateSessionAsync(new SessionConfig +
+Java + +```java +import com.github.copilot.sdk.*; +import com.github.copilot.sdk.json.*; +import java.util.concurrent.CompletableFuture; + +var hooks = new SessionHooks() + .setOnPreToolUse((input, invocation) -> { + System.out.println("[" + invocation.getSessionId() + "] Calling " + input.getToolName()); + System.out.println(" Args: " + input.getToolArgs()); + return CompletableFuture.completedFuture(PreToolUseHookOutput.allow()); + }); + +var session = client.createSession( + new SessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setHooks(hooks) +).get(); +``` + +
+ ### Block Specific Tools ```typescript diff --git a/docs/hooks/session-lifecycle.md b/docs/hooks/session-lifecycle.md index 980b6926bb..da27f4e537 100644 --- a/docs/hooks/session-lifecycle.md +++ b/docs/hooks/session-lifecycle.md @@ -103,6 +103,20 @@ public delegate Task SessionStartHandler( +
+Java + +```java +import com.github.copilot.sdk.json.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiFunction; + +BiFunction> sessionStartHandler; +``` + +
+ ### Input | Field | Type | Description | @@ -304,6 +318,20 @@ public delegate Task SessionEndHandler( +
+Java + +```java +import com.github.copilot.sdk.json.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiFunction; + +BiFunction> sessionEndHandler; +``` + +
+ ### Input | Field | Type | Description | diff --git a/docs/hooks/user-prompt-submitted.md b/docs/hooks/user-prompt-submitted.md index 5065c5efdb..0c4f30eaa1 100644 --- a/docs/hooks/user-prompt-submitted.md +++ b/docs/hooks/user-prompt-submitted.md @@ -99,6 +99,20 @@ public delegate Task UserPromptSubmittedHandler( +
+Java + +```java +import com.github.copilot.sdk.json.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiFunction; + +BiFunction> userPromptSubmittedHandler; +``` + +
+ ## Input | Field | Type | Description | @@ -236,6 +250,29 @@ var session = await client.CreateSessionAsync(new SessionConfig +
+Java + +```java +import com.github.copilot.sdk.*; +import com.github.copilot.sdk.json.*; +import java.util.concurrent.CompletableFuture; + +var hooks = new SessionHooks() + .setOnUserPromptSubmitted((input, invocation) -> { + System.out.println("[" + invocation.getSessionId() + "] User: " + input.getPrompt()); + return CompletableFuture.completedFuture(null); + }); + +var session = client.createSession( + new SessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setHooks(hooks) +).get(); +``` + +
+ ### Add Project Context ```typescript diff --git a/docs/integrations/microsoft-agent-framework.md b/docs/integrations/microsoft-agent-framework.md index 8e794759b7..d6ded461d3 100644 --- a/docs/integrations/microsoft-agent-framework.md +++ b/docs/integrations/microsoft-agent-framework.md @@ -13,7 +13,7 @@ The Microsoft Agent Framework is the unified successor to Semantic Kernel and Au | **Orchestrator** | A MAF component that coordinates agents in sequential, concurrent, or handoff workflows | | **A2A protocol** | Agent-to-Agent communication standard supported by the framework | -> **Note:** MAF integration packages are available for **.NET** and **Python**. For TypeScript and Go, use the Copilot SDK directly — the standard SDK APIs already provide tool calling, streaming, and custom agents. +> **Note:** MAF integration packages are available for **.NET** and **Python**. For TypeScript, Go, and Java, use the Copilot SDK directly — the standard SDK APIs already provide tool calling, streaming, and custom agents. ## Prerequisites @@ -46,6 +46,21 @@ pip install copilot-sdk agent-framework-github-copilot +
+Java + +> **Note:** The Java SDK does not have a dedicated MAF integration package. Use the standard Copilot SDK directly — it provides tool calling, streaming, and custom agents out of the box. + +```xml + + + com.github.copilot + copilot-sdk + +``` + +
+ ## Basic Usage Wrap the Copilot SDK client as a MAF agent with a single method call. The resulting agent conforms to the framework's standard interface and can be used anywhere a MAF agent is expected. @@ -92,6 +107,32 @@ async def main(): +
+Java + + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; + +var client = new CopilotClient(); +client.start().get(); + +var session = client.createSession(new SessionConfig() + .setModel("gpt-4.1") + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) +).get(); + +var response = session.sendAndWait(new MessageOptions() + .setPrompt("Explain how dependency injection works in Spring Boot")).get(); +System.out.println(response.getData().getContent()); + +client.stop().get(); +``` + +
+ ## Adding Custom Tools Extend your Copilot agent with custom function tools. Tools defined through the standard Copilot SDK are automatically available when the agent runs inside MAF. @@ -180,6 +221,44 @@ await session.sendAndWait({ prompt: "What's the weather like in Seattle?" }); +
+Java + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; + +var getWeather = new ToolDefinition() + .setName("GetWeather") + .setDescription("Get the current weather for a given location.") + .setParameters(Map.of( + "type", "object", + "properties", Map.of( + "location", Map.of("type", "string", "description", "City name")), + "required", List.of("location"))); + +var client = new CopilotClient(); +client.start().get(); + +var session = client.createSession(new SessionConfig() + .setModel("gpt-4.1") + .setTools(List.of(getWeather)) + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) +).get(); + +session.registerToolHandler("GetWeather", (args, invocation) -> { + var location = args.get("location").toString(); + return CompletableFuture.completedFuture( + "The weather in " + location + " is sunny, 25°C."); +}); + +session.sendAndWait(new MessageOptions() + .setPrompt("What's the weather like in Seattle?")).get(); +``` + +
+ ## Multi-Agent Workflows The primary benefit of MAF integration is composing Copilot alongside other agent providers in orchestrated workflows. Use the framework's built-in orchestrators to create pipelines where different agents handle different steps. @@ -259,6 +338,44 @@ async def main(): +
+Java + + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; + +// Java uses the standard SDK directly — no MAF orchestrator needed +var client = new CopilotClient(); +client.start().get(); + +// Step 1: Code review session +var reviewer = client.createSession(new SessionConfig() + .setModel("gpt-4.1") + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) +).get(); + +var review = reviewer.sendAndWait(new MessageOptions() + .setPrompt("Review this PR for bugs, security issues, and best practices: " + + "added retry logic to the HTTP client")).get(); + +// Step 2: Documentation session using review output +var documentor = client.createSession(new SessionConfig() + .setModel("gpt-4.1") + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) +).get(); + +var docs = documentor.sendAndWait(new MessageOptions() + .setPrompt("Write documentation for these changes: " + review.getData().getContent())).get(); +System.out.println(docs.getData().getContent()); + +client.stop().get(); +``` + +
+ ### Concurrent Workflow Run multiple agents in parallel and aggregate their results: @@ -296,6 +413,46 @@ Console.WriteLine(combinedResult); +
+Java + + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; +import java.util.concurrent.CompletableFuture; + +// Java uses CompletableFuture for concurrent execution +var client = new CopilotClient(); +client.start().get(); + +var securitySession = client.createSession(new SessionConfig() + .setModel("gpt-4.1") + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) +).get(); + +var perfSession = client.createSession(new SessionConfig() + .setModel("gpt-4.1") + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) +).get(); + +// Run both reviews concurrently +var securityFuture = securitySession.sendAndWait(new MessageOptions() + .setPrompt("Focus on security vulnerabilities in this database query module")); +var perfFuture = perfSession.sendAndWait(new MessageOptions() + .setPrompt("Focus on performance bottlenecks in this database query module")); + +CompletableFuture.allOf(securityFuture, perfFuture).get(); + +System.out.println("Security: " + securityFuture.get().getData().getContent()); +System.out.println("Performance: " + perfFuture.get().getData().getContent()); + +client.stop().get(); +``` + +
+ ## Streaming Responses When building interactive applications, stream agent responses to show real-time output. The MAF integration preserves the Copilot SDK's streaming capabilities. @@ -369,6 +526,36 @@ await session.sendAndWait({ prompt: "Write a quicksort implementation in TypeScr +
+Java + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; + +var client = new CopilotClient(); +client.start().get(); + +var session = client.createSession(new SessionConfig() + .setModel("gpt-4.1") + .setStreaming(true) + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) +).get(); + +session.on("assistant.message_delta", event -> { + System.out.print(event.getData().getDelta()); +}); + +session.sendAndWait(new MessageOptions() + .setPrompt("Write a quicksort implementation in Java")).get(); +System.out.println(); + +client.stop().get(); +``` + +
+ ## Configuration Reference ### MAF Agent Options diff --git a/docs/observability/opentelemetry.md b/docs/observability/opentelemetry.md index b59e61a4cd..9f2374c4d1 100644 --- a/docs/observability/opentelemetry.md +++ b/docs/observability/opentelemetry.md @@ -68,15 +68,32 @@ var client = new CopilotClient(new CopilotClientOptions +
+Java + + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.CopilotClientOptions; +import com.github.copilot.sdk.json.*; + +var client = new CopilotClient(new CopilotClientOptions() + .setTelemetry(new TelemetryConfig() + .setOtlpEndpoint("http://localhost:4318")) +); +``` + +
+ ### TelemetryConfig Options -| Option | Node.js | Python | Go | .NET | Description | -|---|---|---|---|---|---| -| OTLP endpoint | `otlpEndpoint` | `otlp_endpoint` | `OTLPEndpoint` | `OtlpEndpoint` | OTLP HTTP endpoint URL | -| File path | `filePath` | `file_path` | `FilePath` | `FilePath` | File path for JSON-lines trace output | -| Exporter type | `exporterType` | `exporter_type` | `ExporterType` | `ExporterType` | `"otlp-http"` or `"file"` | -| Source name | `sourceName` | `source_name` | `SourceName` | `SourceName` | Instrumentation scope name | -| Capture content | `captureContent` | `capture_content` | `CaptureContent` | `CaptureContent` | Whether to capture message content | +| Option | Node.js | Python | Go | .NET | Java | Description | +|---|---|---|---|---|---|---| +| OTLP endpoint | `otlpEndpoint` | `otlp_endpoint` | `OTLPEndpoint` | `OtlpEndpoint` | `otlpEndpoint` | OTLP HTTP endpoint URL | +| File path | `filePath` | `file_path` | `FilePath` | `FilePath` | `filePath` | File path for JSON-lines trace output | +| Exporter type | `exporterType` | `exporter_type` | `ExporterType` | `ExporterType` | `exporterType` | `"otlp-http"` or `"file"` | +| Source name | `sourceName` | `source_name` | `SourceName` | `SourceName` | `sourceName` | Instrumentation scope name | +| Capture content | `captureContent` | `capture_content` | `CaptureContent` | `CaptureContent` | `captureContent` | Whether to capture message content | ### Trace Context Propagation @@ -149,6 +166,7 @@ session.registerTool(myTool, async (args, invocation) => { | Python | `opentelemetry-api` | Install with `pip install copilot-sdk[telemetry]` | | Go | `go.opentelemetry.io/otel` | Required dependency | | .NET | — | Uses built-in `System.Diagnostics.Activity` | +| Java | — | Trace context injection is automatic when OpenTelemetry Java agent or SDK is configured | ## References diff --git a/docs/setup/backend-services.md b/docs/setup/backend-services.md index 96d8adafcf..03eb6de149 100644 --- a/docs/setup/backend-services.md +++ b/docs/setup/backend-services.md @@ -223,6 +223,31 @@ var response = await session.SendAndWaitAsync( +
+Java + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.CopilotClientOptions; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; + +var client = new CopilotClient(new CopilotClientOptions() + .setCliUrl("localhost:4321") +); +client.start().get(); + +var session = client.createSession(new SessionConfig() + .setSessionId(String.format("user-%s-%d", userId, System.currentTimeMillis() / 1000)) + .setModel("gpt-4.1") +).get(); + +var response = session.sendAndWait(new MessageOptions() + .setPrompt(message)).get(); +``` + +
+ ## Authentication for Backend Services ### Environment Variable Tokens diff --git a/docs/setup/bundled-cli.md b/docs/setup/bundled-cli.md index 289857182a..b52897adc1 100644 --- a/docs/setup/bundled-cli.md +++ b/docs/setup/bundled-cli.md @@ -170,6 +170,35 @@ Console.WriteLine(response?.Data.Content); +
+Java + +> **Note:** The Java SDK does not bundle or embed the Copilot CLI. You must install the CLI separately and configure its path via `cliPath` or the `COPILOT_CLI_PATH` environment variable. + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.CopilotClientOptions; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; + +var client = new CopilotClient(new CopilotClientOptions() + // Point to the CLI binary installed on the system + .setCliPath("/path/to/vendor/copilot") +); +client.start().get(); + +var session = client.createSession(new SessionConfig() + .setModel("gpt-4.1")).get(); + +var response = session.sendAndWait(new MessageOptions() + .setPrompt("Hello!")).get(); +System.out.println(response.getData().getContent()); + +client.stop().get(); +``` + +
+ ## Authentication Strategies When bundling, you need to decide how your users will authenticate. Here are the common patterns: diff --git a/docs/setup/github-oauth.md b/docs/setup/github-oauth.md index e9bb581b9d..d72a2ff136 100644 --- a/docs/setup/github-oauth.md +++ b/docs/setup/github-oauth.md @@ -275,6 +275,38 @@ var response = await session.SendAndWaitAsync( +
+Java + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.CopilotClientOptions; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; + +CopilotClient createClientForUser(String userToken) throws Exception { + var client = new CopilotClient(new CopilotClientOptions() + .setGitHubToken(userToken) + .setUseLoggedInUser(false) + ); + client.start().get(); + return client; +} + +// Usage +var client = createClientForUser("gho_user_access_token"); + +var session = client.createSession(new SessionConfig() + .setSessionId(String.format("user-%s-session", userId)) + .setModel("gpt-4.1") +).get(); + +var response = session.sendAndWait(new MessageOptions() + .setPrompt("Hello!")).get(); +``` + +
+ ## Enterprise & Organization Access GitHub OAuth naturally supports enterprise scenarios. When users authenticate with GitHub, their org memberships and enterprise associations come along. diff --git a/docs/setup/local-cli.md b/docs/setup/local-cli.md index 4b0e5a1cd6..5132434245 100644 --- a/docs/setup/local-cli.md +++ b/docs/setup/local-cli.md @@ -125,6 +125,29 @@ Console.WriteLine(response?.Data.Content); +
+Java + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; + +var client = new CopilotClient(); +client.start().get(); + +var session = client.createSession(new SessionConfig() + .setModel("gpt-4.1")).get(); + +var response = session.sendAndWait(new MessageOptions() + .setPrompt("Hello!")).get(); +System.out.println(response.getData().getContent()); + +client.stop().get(); +``` + +
+ That's it. The SDK handles everything: starting the CLI, authenticating, and managing the session. ## What's Happening Under the Hood diff --git a/docs/troubleshooting/debugging.md b/docs/troubleshooting/debugging.md index 146d3fd5aa..b98777cb5a 100644 --- a/docs/troubleshooting/debugging.md +++ b/docs/troubleshooting/debugging.md @@ -94,6 +94,20 @@ var client = new CopilotClient(new CopilotClientOptions +
+Java + +```java +import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.CopilotClientOptions; + +var client = new CopilotClient(new CopilotClientOptions() + .setLogLevel("debug") +); +``` + +
+ ### Log Directory The CLI writes logs to a directory. You can specify a custom location: @@ -157,6 +171,17 @@ var client = new CopilotClient(new CopilotClientOptions +
+Java + +```java +// The Java SDK does not currently support passing extra CLI arguments. +// For custom log directories, run the CLI manually with --log-dir +// and connect via cliUrl. +``` + +
+ --- ## Common Issues @@ -215,6 +240,16 @@ var client = new CopilotClient(new CopilotClientOptions ``` +
+ Java + + ```java + var client = new CopilotClient(new CopilotClientOptions() + .setCliPath("/usr/local/bin/copilot") + ); + ``` +
+ ### "Not authenticated" **Cause:** The CLI is not authenticated with GitHub. @@ -268,6 +303,16 @@ var client = new CopilotClient(new CopilotClientOptions ``` +
+ Java + + ```java + var client = new CopilotClient(new CopilotClientOptions() + .setGitHubToken(System.getenv("GITHUB_TOKEN")) + ); + ``` +
+ ### "Session not found" **Cause:** Attempting to use a session that was destroyed or doesn't exist. From c6e8fdc8797a853af241d31cb8beee9156f2619a Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Mon, 6 Apr 2026 14:11:11 -0400 Subject: [PATCH 02/13] Update docs/setup/local-cli.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/setup/local-cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/setup/local-cli.md b/docs/setup/local-cli.md index 5132434245..ee7f691865 100644 --- a/docs/setup/local-cli.md +++ b/docs/setup/local-cli.md @@ -141,7 +141,7 @@ var session = client.createSession(new SessionConfig() var response = session.sendAndWait(new MessageOptions() .setPrompt("Hello!")).get(); -System.out.println(response.getData().getContent()); +System.out.println(response.data().content()); client.stop().get(); ``` From 00f828e15dc83c4029a2e0c9490e12937eeca6ba Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Mon, 6 Apr 2026 14:11:31 -0400 Subject: [PATCH 03/13] Update docs/setup/bundled-cli.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/setup/bundled-cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/setup/bundled-cli.md b/docs/setup/bundled-cli.md index b52897adc1..23c71400b1 100644 --- a/docs/setup/bundled-cli.md +++ b/docs/setup/bundled-cli.md @@ -192,7 +192,7 @@ var session = client.createSession(new SessionConfig() var response = session.sendAndWait(new MessageOptions() .setPrompt("Hello!")).get(); -System.out.println(response.getData().getContent()); +System.out.println(response.getData().content()); client.stop().get(); ``` From 905c87792bf5f4c6592a69c5ce8ab5b5136097f4 Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Mon, 6 Apr 2026 14:34:51 -0400 Subject: [PATCH 04/13] Update docs/integrations/microsoft-agent-framework.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/integrations/microsoft-agent-framework.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/integrations/microsoft-agent-framework.md b/docs/integrations/microsoft-agent-framework.md index d6ded461d3..3e9c5d2540 100644 --- a/docs/integrations/microsoft-agent-framework.md +++ b/docs/integrations/microsoft-agent-framework.md @@ -543,8 +543,8 @@ var session = client.createSession(new SessionConfig() .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) ).get(); -session.on("assistant.message_delta", event -> { - System.out.print(event.getData().getDelta()); +session.on(AssistantMessageDeltaEvent.class, event -> { + System.out.print(event.deltaContent()); }); session.sendAndWait(new MessageOptions() From 07af152f4ea5bd809b50b4b2dd17092ccb75836c Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Mon, 6 Apr 2026 14:35:09 -0400 Subject: [PATCH 05/13] Update docs/integrations/microsoft-agent-framework.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/integrations/microsoft-agent-framework.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/integrations/microsoft-agent-framework.md b/docs/integrations/microsoft-agent-framework.md index 3e9c5d2540..50c02f324f 100644 --- a/docs/integrations/microsoft-agent-framework.md +++ b/docs/integrations/microsoft-agent-framework.md @@ -53,9 +53,11 @@ pip install copilot-sdk agent-framework-github-copilot ```xml + - com.github.copilot - copilot-sdk + com.github + copilot-sdk-java + ${copilot.sdk.version} ``` From 63a36a9bedb482926b00a16143ef9092e3ee82e1 Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Mon, 6 Apr 2026 14:40:12 -0400 Subject: [PATCH 06/13] Address review feedback on Java code snippets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix Maven coordinates: com.github:copilot-sdk-java with version property - Fix accessor: getContent() → content() (record-style) across all files - Fix accessor: input.toolName() → input.getToolName() (class-style) - Fix accessor: event.deltaContent() → event.getData().deltaContent() - Fix ToolDefinition: use factory method create() instead of constructor - Add missing imports (json.*, events.*) to feature doc snippets - Add client.start().get() and try-with-resources to hooks quickstart - Wrap OAuth usage example in try-with-resources --- docs/auth/byok.md | 2 +- docs/features/custom-agents.md | 2 + docs/features/hooks.md | 6 +- docs/features/image-input.md | 4 ++ docs/features/skills.md | 2 + docs/features/steering-and-queueing.md | 4 ++ docs/getting-started.md | 8 +-- docs/hooks/index.md | 42 ++++++------- .../integrations/microsoft-agent-framework.md | 59 ++++++++++--------- docs/setup/github-oauth.md | 20 +++---- 10 files changed, 83 insertions(+), 66 deletions(-) diff --git a/docs/auth/byok.md b/docs/auth/byok.md index 6965404a16..962a95ef86 100644 --- a/docs/auth/byok.md +++ b/docs/auth/byok.md @@ -188,7 +188,7 @@ var session = client.createSession(new SessionConfig() var response = session.sendAndWait(new MessageOptions() .setPrompt("What is 2+2?")).get(); -System.out.println(response.getData().getContent()); +System.out.println(response.getData().content()); client.stop().get(); ``` diff --git a/docs/features/custom-agents.md b/docs/features/custom-agents.md index 6fae2fd193..569930cbb9 100644 --- a/docs/features/custom-agents.md +++ b/docs/features/custom-agents.md @@ -210,6 +210,8 @@ await using var session = await client.CreateSessionAsync(new SessionConfig ```java import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; try (var client = new CopilotClient()) { client.start().get(); diff --git a/docs/features/hooks.md b/docs/features/hooks.md index 840638f5b2..b278f7de0e 100644 --- a/docs/features/hooks.md +++ b/docs/features/hooks.md @@ -200,6 +200,8 @@ var session = await client.CreateSessionAsync(new SessionConfig ```java import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; try (var client = new CopilotClient()) { client.start().get(); @@ -413,12 +415,12 @@ var readOnlyTools = Set.of("read_file", "glob", "grep", "view"); var hooks = new SessionHooks() .setOnPreToolUse((input, invocation) -> { - if (!readOnlyTools.contains(input.toolName())) { + if (!readOnlyTools.contains(input.getToolName())) { return CompletableFuture.completedFuture( new PreToolUseHookOutput() .setPermissionDecision("deny") .setPermissionDecisionReason( - "Only read-only tools are allowed. \"" + input.toolName() + "\" was blocked.") + "Only read-only tools are allowed. \"" + input.getToolName() + "\" was blocked.") ); } return CompletableFuture.completedFuture(PreToolUseHookOutput.allow()); diff --git a/docs/features/image-input.md b/docs/features/image-input.md index 33a55c849b..a5902c0d40 100644 --- a/docs/features/image-input.md +++ b/docs/features/image-input.md @@ -224,6 +224,8 @@ await session.SendAsync(new MessageOptions ```java import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; try (var client = new CopilotClient()) { client.start().get(); @@ -431,6 +433,8 @@ await session.SendAsync(new MessageOptions ```java import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; try (var client = new CopilotClient()) { client.start().get(); diff --git a/docs/features/skills.md b/docs/features/skills.md index 683da5a405..9456d7e7a4 100644 --- a/docs/features/skills.md +++ b/docs/features/skills.md @@ -145,6 +145,8 @@ await session.SendAndWaitAsync(new MessageOptions ```java import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; try (var client = new CopilotClient()) { client.start().get(); diff --git a/docs/features/steering-and-queueing.md b/docs/features/steering-and-queueing.md index c3f1e98576..f4acd00069 100644 --- a/docs/features/steering-and-queueing.md +++ b/docs/features/steering-and-queueing.md @@ -183,6 +183,8 @@ await session.SendAsync(new MessageOptions ```java import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; try (var client = new CopilotClient()) { client.start().get(); @@ -423,6 +425,8 @@ await session.SendAsync(new MessageOptions ```java import com.github.copilot.sdk.CopilotClient; +import com.github.copilot.sdk.events.*; +import com.github.copilot.sdk.json.*; try (var client = new CopilotClient()) { client.start().get(); diff --git a/docs/getting-started.md b/docs/getting-started.md index ceb87e90a9..8cbfdfc9fd 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -101,16 +101,16 @@ First, create a new directory and initialize your project. ```xml - com.github.copilot - copilot-sdk - LATEST + com.github + copilot-sdk-java + ${copilot.sdk.version} ``` **Gradle** — add to your `build.gradle`: ```groovy -implementation 'com.github.copilot:copilot-sdk:LATEST' +implementation 'com.github:copilot-sdk-java:${copilotSdkVersion}' ``` diff --git a/docs/hooks/index.md b/docs/hooks/index.md index 3d1c11e151..89fbafde92 100644 --- a/docs/hooks/index.md +++ b/docs/hooks/index.md @@ -164,27 +164,29 @@ import com.github.copilot.sdk.*; import com.github.copilot.sdk.json.*; import java.util.concurrent.CompletableFuture; -var client = new CopilotClient(); +try (var client = new CopilotClient()) { + client.start().get(); -var hooks = new SessionHooks() - .setOnPreToolUse((input, invocation) -> { - System.out.println("Tool called: " + input.getToolName()); - return CompletableFuture.completedFuture(PreToolUseHookOutput.allow()); - }) - .setOnPostToolUse((input, invocation) -> { - System.out.println("Tool result: " + input.getToolResult()); - return CompletableFuture.completedFuture(null); - }) - .setOnSessionStart((input, invocation) -> { - return CompletableFuture.completedFuture( - new SessionStartHookOutput().setAdditionalContext("User prefers concise answers.") - ); - }); - -var session = client.createSession( - new SessionConfig() - .setHooks(hooks) -).get(); + var hooks = new SessionHooks() + .setOnPreToolUse((input, invocation) -> { + System.out.println("Tool called: " + input.getToolName()); + return CompletableFuture.completedFuture(PreToolUseHookOutput.allow()); + }) + .setOnPostToolUse((input, invocation) -> { + System.out.println("Tool result: " + input.getToolResult()); + return CompletableFuture.completedFuture(null); + }) + .setOnSessionStart((input, invocation) -> { + return CompletableFuture.completedFuture( + new SessionStartHookOutput().setAdditionalContext("User prefers concise answers.") + ); + }); + + var session = client.createSession( + new SessionConfig() + .setHooks(hooks) + ).get(); +} ``` diff --git a/docs/integrations/microsoft-agent-framework.md b/docs/integrations/microsoft-agent-framework.md index 50c02f324f..01c785f27f 100644 --- a/docs/integrations/microsoft-agent-framework.md +++ b/docs/integrations/microsoft-agent-framework.md @@ -128,7 +128,7 @@ var session = client.createSession(new SessionConfig() var response = session.sendAndWait(new MessageOptions() .setPrompt("Explain how dependency injection works in Spring Boot")).get(); -System.out.println(response.getData().getContent()); +System.out.println(response.getData().content()); client.stop().get(); ``` @@ -230,33 +230,34 @@ await session.sendAndWait({ prompt: "What's the weather like in Seattle?" }); import com.github.copilot.sdk.CopilotClient; import com.github.copilot.sdk.events.*; import com.github.copilot.sdk.json.*; +import java.util.concurrent.CompletableFuture; -var getWeather = new ToolDefinition() - .setName("GetWeather") - .setDescription("Get the current weather for a given location.") - .setParameters(Map.of( +var getWeather = ToolDefinition.create( + "GetWeather", + "Get the current weather for a given location.", + Map.of( "type", "object", "properties", Map.of( "location", Map.of("type", "string", "description", "City name")), - "required", List.of("location"))); - -var client = new CopilotClient(); -client.start().get(); - -var session = client.createSession(new SessionConfig() - .setModel("gpt-4.1") - .setTools(List.of(getWeather)) - .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) -).get(); - -session.registerToolHandler("GetWeather", (args, invocation) -> { - var location = args.get("location").toString(); - return CompletableFuture.completedFuture( - "The weather in " + location + " is sunny, 25°C."); -}); - -session.sendAndWait(new MessageOptions() - .setPrompt("What's the weather like in Seattle?")).get(); + "required", List.of("location")), + invocation -> { + var location = (String) invocation.getArguments().get("location"); + return CompletableFuture.completedFuture( + "The weather in " + location + " is sunny, 25°C."); + }); + +try (var client = new CopilotClient()) { + client.start().get(); + + var session = client.createSession(new SessionConfig() + .setModel("gpt-4.1") + .setTools(List.of(getWeather)) + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + ).get(); + + session.sendAndWait(new MessageOptions() + .setPrompt("What's the weather like in Seattle?")).get(); +} ``` @@ -370,8 +371,8 @@ var documentor = client.createSession(new SessionConfig() ).get(); var docs = documentor.sendAndWait(new MessageOptions() - .setPrompt("Write documentation for these changes: " + review.getData().getContent())).get(); -System.out.println(docs.getData().getContent()); + .setPrompt("Write documentation for these changes: " + review.getData().content())).get(); +System.out.println(docs.getData().content()); client.stop().get(); ``` @@ -447,8 +448,8 @@ var perfFuture = perfSession.sendAndWait(new MessageOptions() CompletableFuture.allOf(securityFuture, perfFuture).get(); -System.out.println("Security: " + securityFuture.get().getData().getContent()); -System.out.println("Performance: " + perfFuture.get().getData().getContent()); +System.out.println("Security: " + securityFuture.get().getData().content()); +System.out.println("Performance: " + perfFuture.get().getData().content()); client.stop().get(); ``` @@ -546,7 +547,7 @@ var session = client.createSession(new SessionConfig() ).get(); session.on(AssistantMessageDeltaEvent.class, event -> { - System.out.print(event.deltaContent()); + System.out.print(event.getData().deltaContent()); }); session.sendAndWait(new MessageOptions() diff --git a/docs/setup/github-oauth.md b/docs/setup/github-oauth.md index d72a2ff136..f5b2f58bd1 100644 --- a/docs/setup/github-oauth.md +++ b/docs/setup/github-oauth.md @@ -293,16 +293,16 @@ CopilotClient createClientForUser(String userToken) throws Exception { return client; } -// Usage -var client = createClientForUser("gho_user_access_token"); - -var session = client.createSession(new SessionConfig() - .setSessionId(String.format("user-%s-session", userId)) - .setModel("gpt-4.1") -).get(); - -var response = session.sendAndWait(new MessageOptions() - .setPrompt("Hello!")).get(); +// Usage — use try-with-resources to ensure cleanup +try (var client = createClientForUser("gho_user_access_token")) { + var session = client.createSession(new SessionConfig() + .setSessionId(String.format("user-%s-session", userId)) + .setModel("gpt-4.1") + ).get(); + + var response = session.sendAndWait(new MessageOptions() + .setPrompt("Hello!")).get(); +} ``` From 692f764c8ae685011763b5ac528199eea0e23f16 Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Mon, 6 Apr 2026 15:07:30 -0400 Subject: [PATCH 07/13] fix: audit Java code samples against SDK implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix PreToolUseHookOutput: record cannot use setters, use deny() factory - Fix SessionStartHookOutput: record cannot use setters, use constructor - Fix session.getId() → session.getSessionId() - Fix input.getPrompt() → input.prompt() (record accessor) - Fix response.data() → response.getData() (class accessor) - Fix setOnListModels: wrap return in CompletableFuture.completedFuture() - Fix custom-agents event handler: use instanceof pattern matching (AbstractSessionEvent has no getData() method) - Fix streaming-events: remove event.getData() from generic handler - Fix SubagentCompleted/Failed: use agentName() not agentDisplayName() - Fix CopilotClientOptions import: class is in json package, not sdk - Fix hook type signatures: use PreToolUseHandler etc. instead of BiFunction --- docs/auth/byok.md | 8 ++++---- docs/auth/index.md | 4 ++-- docs/features/custom-agents.md | 30 +++++++++++++---------------- docs/features/hooks.md | 6 ++---- docs/features/streaming-events.md | 2 +- docs/getting-started.md | 4 ++-- docs/hooks/error-handling.md | 2 +- docs/hooks/index.md | 2 +- docs/hooks/post-tool-use.md | 5 +---- docs/hooks/pre-tool-use.md | 5 +---- docs/hooks/session-lifecycle.md | 10 ++-------- docs/hooks/user-prompt-submitted.md | 7 ++----- docs/observability/opentelemetry.md | 1 - docs/setup/backend-services.md | 1 - docs/setup/bundled-cli.md | 1 - docs/setup/github-oauth.md | 1 - docs/setup/local-cli.md | 2 +- docs/troubleshooting/debugging.md | 2 +- 18 files changed, 34 insertions(+), 59 deletions(-) diff --git a/docs/auth/byok.md b/docs/auth/byok.md index 962a95ef86..83602c5743 100644 --- a/docs/auth/byok.md +++ b/docs/auth/byok.md @@ -169,7 +169,6 @@ Console.WriteLine(response?.Data.Content); ```java import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.CopilotClientOptions; import com.github.copilot.sdk.events.*; import com.github.copilot.sdk.json.*; @@ -448,17 +447,18 @@ var client = new CopilotClient(new CopilotClientOptions ```java import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.CopilotClientOptions; +import com.github.copilot.sdk.json.*; +import java.util.concurrent.CompletableFuture; var client = new CopilotClient(new CopilotClientOptions() - .setOnListModels(() -> List.of( + .setOnListModels(() -> CompletableFuture.completedFuture(List.of( new ModelInfo() .setId("my-custom-model") .setName("My Custom Model") .setCapabilities(new ModelCapabilities() .setSupports(new ModelSupports().setVision(false).setReasoningEffort(false)) .setLimits(new ModelLimits().setMaxContextWindowTokens(128000))) - )) + ))) ); ``` diff --git a/docs/auth/index.md b/docs/auth/index.md index f06af961eb..069556a9b6 100644 --- a/docs/auth/index.md +++ b/docs/auth/index.md @@ -207,7 +207,7 @@ await using var client = new CopilotClient(new CopilotClientOptions ```java import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.CopilotClientOptions; +import com.github.copilot.sdk.json.*; var client = new CopilotClient(new CopilotClientOptions() .setGitHubToken(userAccessToken) // Token from OAuth flow @@ -385,7 +385,7 @@ await using var client = new CopilotClient(new CopilotClientOptions ```java import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.CopilotClientOptions; +import com.github.copilot.sdk.json.*; var client = new CopilotClient(new CopilotClientOptions() .setUseLoggedInUser(false) // Only use explicit tokens diff --git a/docs/features/custom-agents.md b/docs/features/custom-agents.md index 569930cbb9..cc5d709213 100644 --- a/docs/features/custom-agents.md +++ b/docs/features/custom-agents.md @@ -623,23 +623,19 @@ await session.SendAndWaitAsync(new MessageOptions ```java session.on(event -> { - switch (event.getType()) { - case "subagent.started" -> { - System.out.println("▶ Sub-agent started: " + event.getData().agentDisplayName()); - System.out.println(" Description: " + event.getData().agentDescription()); - System.out.println(" Tool call ID: " + event.getData().toolCallId()); - } - case "subagent.completed" -> - System.out.println("✅ Sub-agent completed: " + event.getData().agentDisplayName()); - case "subagent.failed" -> { - System.out.println("❌ Sub-agent failed: " + event.getData().agentDisplayName()); - System.out.println(" Error: " + event.getData().error()); - } - case "subagent.selected" -> - System.out.println("🎯 Agent selected: " + event.getData().agentDisplayName()); - case "subagent.deselected" -> - System.out.println("↩ Agent deselected, returning to parent"); - default -> {} + if (event instanceof SubagentStartedEvent e) { + System.out.println("▶ Sub-agent started: " + e.getData().agentDisplayName()); + System.out.println(" Description: " + e.getData().agentDescription()); + System.out.println(" Tool call ID: " + e.getData().toolCallId()); + } else if (event instanceof SubagentCompletedEvent e) { + System.out.println("✅ Sub-agent completed: " + e.getData().agentName()); + } else if (event instanceof SubagentFailedEvent e) { + System.out.println("❌ Sub-agent failed: " + e.getData().agentName()); + System.out.println(" Error: " + e.getData().error()); + } else if (event instanceof SubagentSelectedEvent e) { + System.out.println("🎯 Agent selected: " + e.getData().agentDisplayName()); + } else if (event instanceof SubagentDeselectedEvent e) { + System.out.println("↩ Agent deselected, returning to parent"); } }); diff --git a/docs/features/hooks.md b/docs/features/hooks.md index b278f7de0e..e1b9d88d8f 100644 --- a/docs/features/hooks.md +++ b/docs/features/hooks.md @@ -417,10 +417,8 @@ var hooks = new SessionHooks() .setOnPreToolUse((input, invocation) -> { if (!readOnlyTools.contains(input.getToolName())) { return CompletableFuture.completedFuture( - new PreToolUseHookOutput() - .setPermissionDecision("deny") - .setPermissionDecisionReason( - "Only read-only tools are allowed. \"" + input.getToolName() + "\" was blocked.") + PreToolUseHookOutput.deny( + "Only read-only tools are allowed. \"" + input.getToolName() + "\" was blocked.") ); } return CompletableFuture.completedFuture(PreToolUseHookOutput.allow()); diff --git a/docs/features/streaming-events.md b/docs/features/streaming-events.md index cb069ff70b..926af1b9ef 100644 --- a/docs/features/streaming-events.md +++ b/docs/features/streaming-events.md @@ -196,7 +196,7 @@ session.On(evt => ```java // All events -session.on(event -> System.out.println(event.getType() + " " + event.getData())); +session.on(event -> System.out.println(event.getType())); // Specific event type — data is narrowed to the matching class session.on(AssistantMessageDeltaEvent.class, event -> diff --git a/docs/getting-started.md b/docs/getting-started.md index 8cbfdfc9fd..82c5029f20 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -1707,7 +1707,7 @@ await using var session = await client.CreateSessionAsync(new() ```java import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.CopilotClientOptions; +import com.github.copilot.sdk.json.*; var client = new CopilotClient( new CopilotClientOptions().setCliUrl("localhost:4321") @@ -1811,7 +1811,7 @@ No extra dependencies — uses built-in `System.Diagnostics.Activity`. ```java import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.CopilotClientOptions; +import com.github.copilot.sdk.json.*; var client = new CopilotClient(new CopilotClientOptions() .setTelemetry(new TelemetryConfig() diff --git a/docs/hooks/error-handling.md b/docs/hooks/error-handling.md index ed97d6202d..e66dc32ffa 100644 --- a/docs/hooks/error-handling.md +++ b/docs/hooks/error-handling.md @@ -284,7 +284,7 @@ var session = client.createSession( session.setEventErrorPolicy(EventErrorPolicy.SUPPRESS_AND_LOG_ERRORS); session.setEventErrorHandler((event, ex) -> { - System.err.println("[" + session.getId() + "] Error: " + ex.getMessage()); + System.err.println("[" + session.getSessionId() + "] Error: " + ex.getMessage()); System.err.println(" Event: " + event.getType()); }); ``` diff --git a/docs/hooks/index.md b/docs/hooks/index.md index 89fbafde92..b5b711888d 100644 --- a/docs/hooks/index.md +++ b/docs/hooks/index.md @@ -178,7 +178,7 @@ try (var client = new CopilotClient()) { }) .setOnSessionStart((input, invocation) -> { return CompletableFuture.completedFuture( - new SessionStartHookOutput().setAdditionalContext("User prefers concise answers.") + new SessionStartHookOutput("User prefers concise answers.", null) ); }); diff --git a/docs/hooks/post-tool-use.md b/docs/hooks/post-tool-use.md index e3ff11a28a..f7c4089c92 100644 --- a/docs/hooks/post-tool-use.md +++ b/docs/hooks/post-tool-use.md @@ -104,11 +104,8 @@ public delegate Task PostToolUseHandler( ```java import com.github.copilot.sdk.json.*; -import java.util.concurrent.CompletableFuture; -import java.util.function.BiFunction; -BiFunction> postToolUseHandler; +PostToolUseHandler postToolUseHandler; ``` diff --git a/docs/hooks/pre-tool-use.md b/docs/hooks/pre-tool-use.md index 286bb1cfb8..c8e8504f07 100644 --- a/docs/hooks/pre-tool-use.md +++ b/docs/hooks/pre-tool-use.md @@ -104,11 +104,8 @@ public delegate Task PreToolUseHandler( ```java import com.github.copilot.sdk.json.*; -import java.util.concurrent.CompletableFuture; -import java.util.function.BiFunction; -BiFunction> preToolUseHandler; +PreToolUseHandler preToolUseHandler; ``` diff --git a/docs/hooks/session-lifecycle.md b/docs/hooks/session-lifecycle.md index da27f4e537..1c8723854f 100644 --- a/docs/hooks/session-lifecycle.md +++ b/docs/hooks/session-lifecycle.md @@ -108,11 +108,8 @@ public delegate Task SessionStartHandler( ```java import com.github.copilot.sdk.json.*; -import java.util.concurrent.CompletableFuture; -import java.util.function.BiFunction; -BiFunction> sessionStartHandler; +SessionStartHandler sessionStartHandler; ``` @@ -323,11 +320,8 @@ public delegate Task SessionEndHandler( ```java import com.github.copilot.sdk.json.*; -import java.util.concurrent.CompletableFuture; -import java.util.function.BiFunction; -BiFunction> sessionEndHandler; +SessionEndHandler sessionEndHandler; ``` diff --git a/docs/hooks/user-prompt-submitted.md b/docs/hooks/user-prompt-submitted.md index 0c4f30eaa1..0c0751980e 100644 --- a/docs/hooks/user-prompt-submitted.md +++ b/docs/hooks/user-prompt-submitted.md @@ -104,11 +104,8 @@ public delegate Task UserPromptSubmittedHandler( ```java import com.github.copilot.sdk.json.*; -import java.util.concurrent.CompletableFuture; -import java.util.function.BiFunction; -BiFunction> userPromptSubmittedHandler; +UserPromptSubmittedHandler userPromptSubmittedHandler; ``` @@ -260,7 +257,7 @@ import java.util.concurrent.CompletableFuture; var hooks = new SessionHooks() .setOnUserPromptSubmitted((input, invocation) -> { - System.out.println("[" + invocation.getSessionId() + "] User: " + input.getPrompt()); + System.out.println("[" + invocation.getSessionId() + "] User: " + input.prompt()); return CompletableFuture.completedFuture(null); }); diff --git a/docs/observability/opentelemetry.md b/docs/observability/opentelemetry.md index 9f2374c4d1..cf564cc970 100644 --- a/docs/observability/opentelemetry.md +++ b/docs/observability/opentelemetry.md @@ -74,7 +74,6 @@ var client = new CopilotClient(new CopilotClientOptions ```java import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.CopilotClientOptions; import com.github.copilot.sdk.json.*; var client = new CopilotClient(new CopilotClientOptions() diff --git a/docs/setup/backend-services.md b/docs/setup/backend-services.md index 03eb6de149..3dd1974e8f 100644 --- a/docs/setup/backend-services.md +++ b/docs/setup/backend-services.md @@ -228,7 +228,6 @@ var response = await session.SendAndWaitAsync( ```java import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.CopilotClientOptions; import com.github.copilot.sdk.events.*; import com.github.copilot.sdk.json.*; diff --git a/docs/setup/bundled-cli.md b/docs/setup/bundled-cli.md index 23c71400b1..3360f07769 100644 --- a/docs/setup/bundled-cli.md +++ b/docs/setup/bundled-cli.md @@ -177,7 +177,6 @@ Console.WriteLine(response?.Data.Content); ```java import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.CopilotClientOptions; import com.github.copilot.sdk.events.*; import com.github.copilot.sdk.json.*; diff --git a/docs/setup/github-oauth.md b/docs/setup/github-oauth.md index f5b2f58bd1..200c7dfd42 100644 --- a/docs/setup/github-oauth.md +++ b/docs/setup/github-oauth.md @@ -280,7 +280,6 @@ var response = await session.SendAndWaitAsync( ```java import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.CopilotClientOptions; import com.github.copilot.sdk.events.*; import com.github.copilot.sdk.json.*; diff --git a/docs/setup/local-cli.md b/docs/setup/local-cli.md index ee7f691865..fb937df0b1 100644 --- a/docs/setup/local-cli.md +++ b/docs/setup/local-cli.md @@ -141,7 +141,7 @@ var session = client.createSession(new SessionConfig() var response = session.sendAndWait(new MessageOptions() .setPrompt("Hello!")).get(); -System.out.println(response.data().content()); +System.out.println(response.getData().content()); client.stop().get(); ``` diff --git a/docs/troubleshooting/debugging.md b/docs/troubleshooting/debugging.md index b98777cb5a..802798b219 100644 --- a/docs/troubleshooting/debugging.md +++ b/docs/troubleshooting/debugging.md @@ -99,7 +99,7 @@ var client = new CopilotClient(new CopilotClientOptions ```java import com.github.copilot.sdk.CopilotClient; -import com.github.copilot.sdk.CopilotClientOptions; +import com.github.copilot.sdk.json.*; var client = new CopilotClient(new CopilotClientOptions() .setLogLevel("debug") From 4a7a32d91f7d6ebc01f578989fa2d3a13068261c Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Mon, 6 Apr 2026 15:28:48 -0400 Subject: [PATCH 08/13] Update docs/getting-started.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/getting-started.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/getting-started.md b/docs/getting-started.md index 82c5029f20..6942282754 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -1414,6 +1414,9 @@ public class WeatherAssistant { new SessionConfig() .setModel("gpt-4.1") .setStreaming(true) + .setOnPermissionRequest(request -> + CompletableFuture.completedFuture(PermissionDecision.allow()) + ) .setTools(List.of(getWeather)) ).get(); From a84313490da154fe927216d35a7a76d6b833007a Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Mon, 6 Apr 2026 15:29:10 -0400 Subject: [PATCH 09/13] Update docs/getting-started.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 6942282754..16916dc9d6 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -20,7 +20,7 @@ Before you begin, make sure you have: - **GitHub Copilot CLI** installed and authenticated ([Installation guide](https://docs.github.com/en/copilot/how-tos/set-up/install-copilot-cli)) - Your preferred language runtime: - - **Node.js** 18+ or **Python** 3.8+ or **Go** 1.21+ or **Java** 17+ or **.NET** 8.0+ + - **Node.js** 18+ or **Python** 3.11+ or **Go** 1.21+ or **Java** 17+ or **.NET** 8.0+ Verify the CLI is working: From 59291023ea2ad3c892ff66d99ddb41c2d2b80f6a Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Mon, 6 Apr 2026 15:29:27 -0400 Subject: [PATCH 10/13] Update docs/setup/local-cli.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/setup/local-cli.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/setup/local-cli.md b/docs/setup/local-cli.md index fb937df0b1..d5b168bd28 100644 --- a/docs/setup/local-cli.md +++ b/docs/setup/local-cli.md @@ -137,7 +137,8 @@ var client = new CopilotClient(); client.start().get(); var session = client.createSession(new SessionConfig() - .setModel("gpt-4.1")).get(); + .setModel("gpt-4.1") + .setOnPermissionRequest(request -> PermissionDecision.allow())).get(); var response = session.sendAndWait(new MessageOptions() .setPrompt("Hello!")).get(); From afbc006c4bdc9723a94b794a2a7e8cbf24ce24cb Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Mon, 6 Apr 2026 16:14:43 -0400 Subject: [PATCH 11/13] Update docs/setup/backend-services.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/setup/backend-services.md | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/docs/setup/backend-services.md b/docs/setup/backend-services.md index 3dd1974e8f..b308438801 100644 --- a/docs/setup/backend-services.md +++ b/docs/setup/backend-services.md @@ -234,15 +234,21 @@ import com.github.copilot.sdk.json.*; var client = new CopilotClient(new CopilotClientOptions() .setCliUrl("localhost:4321") ); -client.start().get(); -var session = client.createSession(new SessionConfig() - .setSessionId(String.format("user-%s-%d", userId, System.currentTimeMillis() / 1000)) - .setModel("gpt-4.1") -).get(); +try { + client.start().get(); -var response = session.sendAndWait(new MessageOptions() - .setPrompt(message)).get(); + var session = client.createSession(new SessionConfig() + .setSessionId(String.format("user-%s-%d", userId, System.currentTimeMillis() / 1000)) + .setModel("gpt-4.1") + .setOnPermissionRequest(request -> request.allow()) + ).get(); + + var response = session.sendAndWait(new MessageOptions() + .setPrompt(message)).get(); +} finally { + client.stop().get(); +} ``` From 236901b421f19f4fdb057924f69539c70b0bd840 Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Mon, 6 Apr 2026 16:15:14 -0400 Subject: [PATCH 12/13] Update docs/observability/opentelemetry.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/observability/opentelemetry.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/observability/opentelemetry.md b/docs/observability/opentelemetry.md index cf564cc970..3ac1bca9c3 100644 --- a/docs/observability/opentelemetry.md +++ b/docs/observability/opentelemetry.md @@ -165,7 +165,7 @@ session.registerTool(myTool, async (args, invocation) => { | Python | `opentelemetry-api` | Install with `pip install copilot-sdk[telemetry]` | | Go | `go.opentelemetry.io/otel` | Required dependency | | .NET | — | Uses built-in `System.Diagnostics.Activity` | -| Java | — | Trace context injection is automatic when OpenTelemetry Java agent or SDK is configured | +| Java | `io.opentelemetry:opentelemetry-api` | Add this dependency for SDK-based setup; trace context injection is automatic when the OpenTelemetry Java agent or SDK is configured | ## References From e1fbc2c5e5d1e7a7ba0cc939787be10d696ce00d Mon Sep 17 00:00:00 2001 From: Bruno Borges Date: Mon, 6 Apr 2026 16:15:24 -0400 Subject: [PATCH 13/13] Update docs/getting-started.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/getting-started.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/getting-started.md b/docs/getting-started.md index 16916dc9d6..dea074aeda 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -1019,6 +1019,7 @@ public class HelloCopilot { .setModel("gpt-4.1") .setStreaming(true) .setTools(List.of(getWeather)) + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) ).get(); session.on(AssistantMessageDeltaEvent.class, delta -> {