mirror of
https://github.com/github/awesome-copilot.git
synced 2026-04-11 18:55:55 +00:00
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/.
321 lines
11 KiB
Markdown
321 lines
11 KiB
Markdown
# Session Persistence and Resumption
|
|
|
|
Save and restore conversation sessions across application restarts.
|
|
|
|
> **Runnable example:** [recipe/PersistingSessions.java](recipe/PersistingSessions.java)
|
|
>
|
|
> ```bash
|
|
> jbang recipe/PersistingSessions.java
|
|
> ```
|
|
|
|
## Example scenario
|
|
|
|
You want users to be able to continue a conversation even after closing and reopening your application. The Copilot SDK persists session state to disk automatically — you just need to provide a stable session ID and resume later.
|
|
|
|
## Creating a session with a custom ID
|
|
|
|
```java
|
|
//DEPS com.github:copilot-sdk-java:0.2.1-java.1
|
|
import com.github.copilot.sdk.CopilotClient;
|
|
import com.github.copilot.sdk.events.AssistantMessageEvent;
|
|
import com.github.copilot.sdk.json.MessageOptions;
|
|
import com.github.copilot.sdk.json.PermissionHandler;
|
|
import com.github.copilot.sdk.json.SessionConfig;
|
|
|
|
public class CreateSessionWithId {
|
|
public static void main(String[] args) throws Exception {
|
|
try (var client = new CopilotClient()) {
|
|
client.start().get();
|
|
|
|
// Create session with a memorable ID
|
|
var session = client.createSession(
|
|
new SessionConfig()
|
|
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
|
|
.setSessionId("user-123-conversation")
|
|
.setModel("gpt-5")
|
|
).get();
|
|
|
|
session.on(AssistantMessageEvent.class, msg ->
|
|
System.out.println(msg.getData().content())
|
|
);
|
|
|
|
session.sendAndWait(new MessageOptions()
|
|
.setPrompt("Let's discuss TypeScript generics")).get();
|
|
|
|
// Session ID is preserved
|
|
System.out.println("Session ID: " + session.getSessionId());
|
|
|
|
// Close session but keep data on disk
|
|
session.close();
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Resuming a session
|
|
|
|
```java
|
|
//DEPS com.github:copilot-sdk-java:0.2.1-java.1
|
|
import com.github.copilot.sdk.CopilotClient;
|
|
import com.github.copilot.sdk.events.AssistantMessageEvent;
|
|
import com.github.copilot.sdk.json.MessageOptions;
|
|
import com.github.copilot.sdk.json.PermissionHandler;
|
|
import com.github.copilot.sdk.json.ResumeSessionConfig;
|
|
|
|
public class ResumeSession {
|
|
public static void main(String[] args) throws Exception {
|
|
try (var client = new CopilotClient()) {
|
|
client.start().get();
|
|
|
|
// Resume the previous session
|
|
var session = client.resumeSession(
|
|
"user-123-conversation",
|
|
new ResumeSessionConfig()
|
|
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
|
|
).get();
|
|
|
|
session.on(AssistantMessageEvent.class, msg ->
|
|
System.out.println(msg.getData().content())
|
|
);
|
|
|
|
// Previous context is restored
|
|
session.sendAndWait(new MessageOptions()
|
|
.setPrompt("What were we discussing?")).get();
|
|
|
|
session.close();
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Listing available sessions
|
|
|
|
```java
|
|
//DEPS com.github:copilot-sdk-java:0.2.1-java.1
|
|
import com.github.copilot.sdk.CopilotClient;
|
|
|
|
public class ListSessions {
|
|
public static void main(String[] args) throws Exception {
|
|
try (var client = new CopilotClient()) {
|
|
client.start().get();
|
|
|
|
var sessions = client.listSessions().get();
|
|
for (var sessionInfo : sessions) {
|
|
System.out.println("Session: " + sessionInfo.getSessionId());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Deleting a session permanently
|
|
|
|
```java
|
|
//DEPS com.github:copilot-sdk-java:0.2.1-java.1
|
|
import com.github.copilot.sdk.CopilotClient;
|
|
|
|
public class DeleteSession {
|
|
public static void main(String[] args) throws Exception {
|
|
try (var client = new CopilotClient()) {
|
|
client.start().get();
|
|
|
|
// Remove session and all its data from disk
|
|
client.deleteSession("user-123-conversation").get();
|
|
System.out.println("Session deleted");
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Getting session history
|
|
|
|
```java
|
|
//DEPS com.github:copilot-sdk-java:0.2.1-java.1
|
|
import com.github.copilot.sdk.CopilotClient;
|
|
import com.github.copilot.sdk.events.AssistantMessageEvent;
|
|
import com.github.copilot.sdk.events.UserMessageEvent;
|
|
import com.github.copilot.sdk.json.PermissionHandler;
|
|
import com.github.copilot.sdk.json.ResumeSessionConfig;
|
|
|
|
public class SessionHistory {
|
|
public static void main(String[] args) throws Exception {
|
|
try (var client = new CopilotClient()) {
|
|
client.start().get();
|
|
|
|
var session = client.resumeSession(
|
|
"user-123-conversation",
|
|
new ResumeSessionConfig()
|
|
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
|
|
).get();
|
|
|
|
var messages = session.getMessages().get();
|
|
for (var event : messages) {
|
|
if (event instanceof AssistantMessageEvent msg) {
|
|
System.out.printf("[assistant] %s%n", msg.getData().content());
|
|
} else if (event instanceof UserMessageEvent userMsg) {
|
|
System.out.printf("[user] %s%n", userMsg.getData().content());
|
|
} else {
|
|
System.out.printf("[%s]%n", event.getType());
|
|
}
|
|
}
|
|
|
|
session.close();
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Complete example with session management
|
|
|
|
This interactive example lets you create, resume, or list sessions from the command line.
|
|
|
|
```java
|
|
//DEPS com.github:copilot-sdk-java:0.2.1-java.1
|
|
import com.github.copilot.sdk.CopilotClient;
|
|
import com.github.copilot.sdk.events.AssistantMessageEvent;
|
|
import com.github.copilot.sdk.json.*;
|
|
import java.util.Scanner;
|
|
|
|
public class SessionManager {
|
|
public static void main(String[] args) throws Exception {
|
|
try (var client = new CopilotClient();
|
|
var scanner = new Scanner(System.in)) {
|
|
|
|
client.start().get();
|
|
|
|
System.out.println("Session Manager");
|
|
System.out.println("1. Create new session");
|
|
System.out.println("2. Resume existing session");
|
|
System.out.println("3. List sessions");
|
|
System.out.print("Choose an option: ");
|
|
|
|
int choice = scanner.nextInt();
|
|
scanner.nextLine();
|
|
|
|
switch (choice) {
|
|
case 1 -> {
|
|
System.out.print("Enter session ID: ");
|
|
String sessionId = scanner.nextLine();
|
|
var session = client.createSession(
|
|
new SessionConfig()
|
|
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
|
|
.setSessionId(sessionId)
|
|
.setModel("gpt-5")
|
|
).get();
|
|
|
|
session.on(AssistantMessageEvent.class, msg ->
|
|
System.out.println("\nCopilot: " + msg.getData().content())
|
|
);
|
|
|
|
System.out.println("Created session: " + sessionId);
|
|
chatLoop(session, scanner);
|
|
session.close();
|
|
}
|
|
|
|
case 2 -> {
|
|
System.out.print("Enter session ID to resume: ");
|
|
String resumeId = scanner.nextLine();
|
|
try {
|
|
var session = client.resumeSession(
|
|
resumeId,
|
|
new ResumeSessionConfig()
|
|
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
|
|
).get();
|
|
|
|
session.on(AssistantMessageEvent.class, msg ->
|
|
System.out.println("\nCopilot: " + msg.getData().content())
|
|
);
|
|
|
|
System.out.println("Resumed session: " + resumeId);
|
|
chatLoop(session, scanner);
|
|
session.close();
|
|
} catch (Exception ex) {
|
|
System.err.println("Failed to resume session: " + ex.getMessage());
|
|
}
|
|
}
|
|
|
|
case 3 -> {
|
|
var sessions = client.listSessions().get();
|
|
System.out.println("\nAvailable sessions:");
|
|
for (var s : sessions) {
|
|
System.out.println(" - " + s.getSessionId());
|
|
}
|
|
}
|
|
|
|
default -> System.out.println("Invalid choice");
|
|
}
|
|
}
|
|
}
|
|
|
|
static void chatLoop(Object session, Scanner scanner) throws Exception {
|
|
System.out.println("\nStart chatting (type 'exit' to quit):");
|
|
while (true) {
|
|
System.out.print("\nYou: ");
|
|
String input = scanner.nextLine();
|
|
if (input.equalsIgnoreCase("exit")) break;
|
|
|
|
// Use reflection-free approach: cast to the session type
|
|
var s = (com.github.copilot.sdk.CopilotSession) session;
|
|
s.sendAndWait(new MessageOptions().setPrompt(input)).get();
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Checking if a session exists
|
|
|
|
```java
|
|
//DEPS com.github:copilot-sdk-java:0.2.1-java.1
|
|
import com.github.copilot.sdk.CopilotClient;
|
|
import com.github.copilot.sdk.json.*;
|
|
|
|
public class CheckSession {
|
|
public static boolean sessionExists(CopilotClient client, String sessionId) {
|
|
try {
|
|
var sessions = client.listSessions().get();
|
|
return sessions.stream()
|
|
.anyMatch(s -> s.getSessionId().equals(sessionId));
|
|
} catch (Exception ex) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
try (var client = new CopilotClient()) {
|
|
client.start().get();
|
|
|
|
String sessionId = "user-123-conversation";
|
|
|
|
if (sessionExists(client, sessionId)) {
|
|
System.out.println("Session exists, resuming...");
|
|
var session = client.resumeSession(
|
|
sessionId,
|
|
new ResumeSessionConfig()
|
|
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
|
|
).get();
|
|
// ... use session ...
|
|
session.close();
|
|
} else {
|
|
System.out.println("Session doesn't exist, creating new one...");
|
|
var session = client.createSession(
|
|
new SessionConfig()
|
|
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
|
|
.setSessionId(sessionId)
|
|
.setModel("gpt-5")
|
|
).get();
|
|
// ... use session ...
|
|
session.close();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Best practices
|
|
|
|
1. **Use meaningful session IDs**: Include user ID or context in the session ID (e.g., `"user-123-chat"`, `"task-456-review"`)
|
|
2. **Handle missing sessions**: Check if a session exists before resuming — use `listSessions()` or catch the exception from `resumeSession()`
|
|
3. **Clean up old sessions**: Periodically delete sessions that are no longer needed with `deleteSession()`
|
|
4. **Error handling**: Always wrap resume operations in try-catch blocks — sessions may have been deleted or expired
|
|
5. **Workspace awareness**: Sessions are tied to workspace paths; ensure consistency when resuming across environments
|