mirror of
https://github.com/github/awesome-copilot.git
synced 2026-04-11 18:55:55 +00:00
Add Java SDK cookbook with 7 recipes
Add complete Java cookbook matching the pattern of existing .NET, Go, Node.js, and Python cookbooks. All 7 recipes included: - Ralph Loop: Autonomous AI task loops with JBang - Error Handling: try-with-resources, ExecutionException, timeouts - Multiple Sessions: Parallel sessions with CompletableFuture - Managing Local Files: AI-powered file organization - PR Visualization: Interactive PR age charts - Persisting Sessions: Save/resume with custom IDs - Accessibility Report: WCAG reports via Playwright MCP Each recipe includes both markdown documentation and a standalone JBang-runnable Java file in recipe/.
This commit is contained in:
183
cookbook/copilot-sdk/java/error-handling.md
Normal file
183
cookbook/copilot-sdk/java/error-handling.md
Normal file
@@ -0,0 +1,183 @@
|
||||
# Error Handling Patterns
|
||||
|
||||
Handle errors gracefully in your Copilot SDK applications.
|
||||
|
||||
> **Runnable example:** [recipe/ErrorHandling.java](recipe/ErrorHandling.java)
|
||||
>
|
||||
> ```bash
|
||||
> jbang recipe/ErrorHandling.java
|
||||
> ```
|
||||
|
||||
## Example scenario
|
||||
|
||||
You need to handle various error conditions like connection failures, timeouts, and invalid responses.
|
||||
|
||||
## Basic try-with-resources
|
||||
|
||||
Java's `try-with-resources` ensures the client is always cleaned up, even when exceptions occur.
|
||||
|
||||
```java
|
||||
//DEPS com.github:copilot-sdk-java:0.2.1-java.1
|
||||
|
||||
import com.github.copilot.sdk.*;
|
||||
import com.github.copilot.sdk.json.*;
|
||||
|
||||
public class BasicErrorHandling {
|
||||
public static void main(String[] args) {
|
||||
try (var client = new CopilotClient()) {
|
||||
client.start().get();
|
||||
var session = client.createSession(
|
||||
new SessionConfig()
|
||||
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
|
||||
.setModel("gpt-5")).get();
|
||||
|
||||
var response = session.sendAndWait(
|
||||
new MessageOptions().setPrompt("Hello!")).get();
|
||||
System.out.println(response.getData().content());
|
||||
|
||||
session.close();
|
||||
} catch (Exception ex) {
|
||||
System.err.println("Error: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Handling specific error types
|
||||
|
||||
Every `CompletableFuture.get()` call wraps failures in `ExecutionException`. Unwrap the cause to inspect the real error.
|
||||
|
||||
```java
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
try (var client = new CopilotClient()) {
|
||||
client.start().get();
|
||||
} catch (ExecutionException ex) {
|
||||
var cause = ex.getCause();
|
||||
if (cause instanceof IOException) {
|
||||
System.err.println("Copilot CLI not found or could not connect: " + cause.getMessage());
|
||||
} else {
|
||||
System.err.println("Unexpected error: " + cause.getMessage());
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
System.err.println("Interrupted while starting client.");
|
||||
}
|
||||
```
|
||||
|
||||
## Timeout handling
|
||||
|
||||
Use the overloaded `get(timeout, unit)` on `CompletableFuture` to enforce time limits.
|
||||
|
||||
```java
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
var session = client.createSession(
|
||||
new SessionConfig()
|
||||
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
|
||||
.setModel("gpt-5")).get();
|
||||
|
||||
try {
|
||||
var response = session.sendAndWait(
|
||||
new MessageOptions().setPrompt("Complex question..."))
|
||||
.get(30, TimeUnit.SECONDS);
|
||||
|
||||
System.out.println(response.getData().content());
|
||||
} catch (TimeoutException ex) {
|
||||
System.err.println("Request timed out after 30 seconds.");
|
||||
session.abort().get();
|
||||
}
|
||||
```
|
||||
|
||||
## Aborting a request
|
||||
|
||||
Cancel an in-flight request by calling `session.abort()`.
|
||||
|
||||
```java
|
||||
var session = client.createSession(
|
||||
new SessionConfig()
|
||||
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
|
||||
.setModel("gpt-5")).get();
|
||||
|
||||
// Start a request without waiting
|
||||
session.send(new MessageOptions().setPrompt("Write a very long story..."));
|
||||
|
||||
// Abort after some condition
|
||||
Thread.sleep(5000);
|
||||
session.abort().get();
|
||||
System.out.println("Request aborted.");
|
||||
```
|
||||
|
||||
## Graceful shutdown
|
||||
|
||||
Use a JVM shutdown hook to clean up when the process is interrupted.
|
||||
|
||||
```java
|
||||
var client = new CopilotClient();
|
||||
client.start().get();
|
||||
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
System.out.println("Shutting down...");
|
||||
try {
|
||||
client.close();
|
||||
} catch (Exception ex) {
|
||||
System.err.println("Cleanup error: " + ex.getMessage());
|
||||
}
|
||||
}));
|
||||
```
|
||||
|
||||
## Try-with-resources (nested)
|
||||
|
||||
When working with multiple sessions, nest `try-with-resources` blocks to guarantee each resource is closed.
|
||||
|
||||
```java
|
||||
try (var client = new CopilotClient()) {
|
||||
client.start().get();
|
||||
|
||||
try (var session = client.createSession(
|
||||
new SessionConfig()
|
||||
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
|
||||
.setModel("gpt-5")).get()) {
|
||||
|
||||
session.sendAndWait(
|
||||
new MessageOptions().setPrompt("Hello!")).get();
|
||||
} // session is closed here
|
||||
|
||||
} // client is closed here
|
||||
```
|
||||
|
||||
## Handling tool errors
|
||||
|
||||
When defining tools, return an error result to signal a failure back to the model instead of throwing.
|
||||
|
||||
```java
|
||||
import com.github.copilot.sdk.json.ToolResultObject;
|
||||
|
||||
session.addTool(
|
||||
ToolDefinition.builder()
|
||||
.name("read_file")
|
||||
.description("Read a file from disk")
|
||||
.parameter("path", "string", "File path", true)
|
||||
.build(),
|
||||
(args) -> {
|
||||
try {
|
||||
var content = java.nio.file.Files.readString(
|
||||
java.nio.file.Path.of(args.get("path").toString()));
|
||||
return ToolResultObject.success(content);
|
||||
} catch (IOException ex) {
|
||||
return ToolResultObject.error("Failed to read file: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## Best practices
|
||||
|
||||
1. **Use try-with-resources**: Always wrap `CopilotClient` (and sessions, if `AutoCloseable`) in try-with-resources to guarantee cleanup.
|
||||
2. **Unwrap `ExecutionException`**: Call `getCause()` to inspect the real error — the outer `ExecutionException` is just a `CompletableFuture` wrapper.
|
||||
3. **Restore interrupt flag**: When catching `InterruptedException`, call `Thread.currentThread().interrupt()` to preserve the interrupted status.
|
||||
4. **Set timeouts**: Use `get(timeout, TimeUnit)` instead of bare `get()` for any call that could block indefinitely.
|
||||
5. **Return tool errors, don't throw**: Use `ToolResultObject.error()` so the model can recover gracefully.
|
||||
6. **Log errors**: Capture error details for debugging — consider a logging framework like SLF4J for production applications.
|
||||
Reference in New Issue
Block a user