# Session Persistence and Resumption

Save and restore conversation sessions across application restarts.

## Prerequisites

Install [JBang](https://www.jbang.dev/) to run these examples:

```bash
# macOS (using Homebrew)
brew install jbangdev/tap/jbang

# Linux/macOS (using curl)
curl -Ls https://sh.jbang.dev | bash -s - app setup

# Windows (using Scoop)
scoop install jbang
```

## Example scenario

You want users to be able to continue a conversation even after closing and reopening your application.

## Creating a session with a custom ID

**Usage:**
```bash
jbang PersistingSessions.java
```

**Code:**
```java
//DEPS com.github:copilot-sdk-java:0.2.2-java.1
import com.github.copilot.sdk.CopilotClient;
import com.github.copilot.sdk.events.AssistantMessageEvent;
import com.github.copilot.sdk.json.MessageOptions;
import com.github.copilot.sdk.json.PermissionHandler;
import com.github.copilot.sdk.json.SessionConfig;

public class PersistingSessions {
    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
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
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
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.2-java.1
import com.github.copilot.sdk.CopilotClient;
import com.github.copilot.sdk.events.AssistantMessageEvent;
import com.github.copilot.sdk.events.UserMessageEvent;
import com.github.copilot.sdk.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) {
                // Print different event types appropriately
                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

```java
//DEPS com.github:copilot-sdk-java:0.2.2-java.1
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(); // consume newline

            CopilotSession session = null;

            switch (choice) {
                case 1:
                    System.out.print("Enter session ID: ");
                    String sessionId = scanner.nextLine();
                    session = client.createSession(
                        new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
                            .setSessionId(sessionId)
                            .setModel("gpt-5")
                    ).get();
                    System.out.println("Created session: " + sessionId);
                    break;

                case 2:
                    System.out.print("Enter session ID to resume: ");
                    String resumeId = scanner.nextLine();
                    try {
                        session = client.resumeSession(resumeId, new ResumeSessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get();
                        System.out.println("Resumed session: " + resumeId);
                    } catch (Exception ex) {
                        System.err.println("Failed to resume session: " + ex.getMessage());
                        return;
                    }
                    break;

                case 3:
                    var sessions = client.listSessions().get();
                    System.out.println("\nAvailable sessions:");
                    for (var s : sessions) {
                        System.out.println("  - " + s.getSessionId());
                    }
                    return;

                default:
                    System.out.println("Invalid choice");
                    return;
            }

            if (session != null) {
                session.on(AssistantMessageEvent.class, msg -> 
                    System.out.println("\nCopilot: " + msg.getData().content())
                );

                // Interactive conversation loop
                System.out.println("\nStart chatting (type 'exit' to quit):");
                while (true) {
                    System.out.print("\nYou: ");
                    String input = scanner.nextLine();
                    
                    if (input.equalsIgnoreCase("exit")) {
                        break;
                    }

                    session.send(new MessageOptions().setPrompt(input));
                    Thread.sleep(2000); // Give time for response
                }

                session.close();
            }
        }
    }
}
```

## Checking if a session exists

```java
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
3. **Clean up old sessions**: Periodically delete sessions that are no longer needed
4. **Error handling**: Always wrap resume operations in try-catch blocks
5. **Workspace awareness**: Sessions are tied to workspace paths, ensure consistency
