Skip to content

Commit 212d985

Browse files
committed
feat: add infinite sessions support with workspace persistence
1 parent 6551101 commit 212d985

8 files changed

Lines changed: 294 additions & 2 deletions

File tree

src/main/java/com/github/copilot/sdk/CopilotClient.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -425,10 +425,12 @@ public CompletableFuture<CopilotSession> createSession(SessionConfig config) {
425425
request.setStreaming(config.isStreaming() ? true : null);
426426
request.setMcpServers(config.getMcpServers());
427427
request.setCustomAgents(config.getCustomAgents());
428+
request.setInfiniteSessions(config.getInfiniteSessions());
428429
}
429430

430431
return connection.rpc.invoke("session.create", request, CreateSessionResponse.class).thenApply(response -> {
431-
CopilotSession session = new CopilotSession(response.getSessionId(), connection.rpc);
432+
CopilotSession session = new CopilotSession(response.getSessionId(), connection.rpc,
433+
response.getWorkspacePath());
432434
if (config != null && config.getTools() != null) {
433435
session.registerTools(config.getTools());
434436
}
@@ -484,7 +486,8 @@ public CompletableFuture<CopilotSession> resumeSession(String sessionId, ResumeS
484486
}
485487

486488
return connection.rpc.invoke("session.resume", request, ResumeSessionResponse.class).thenApply(response -> {
487-
CopilotSession session = new CopilotSession(response.getSessionId(), connection.rpc);
489+
CopilotSession session = new CopilotSession(response.getSessionId(), connection.rpc,
490+
response.getWorkspacePath());
488491
if (config != null && config.getTools() != null) {
489492
session.registerTools(config.getTools());
490493
}

src/main/java/com/github/copilot/sdk/CopilotSession.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public final class CopilotSession implements AutoCloseable {
7777
private static final ObjectMapper MAPPER = JsonRpcClient.getObjectMapper();
7878

7979
private final String sessionId;
80+
private final String workspacePath;
8081
private final JsonRpcClient rpc;
8182
private final Set<Consumer<AbstractSessionEvent>> eventHandlers = ConcurrentHashMap.newKeySet();
8283
private final Map<String, ToolDefinition> toolHandlers = new ConcurrentHashMap<>();
@@ -94,8 +95,26 @@ public final class CopilotSession implements AutoCloseable {
9495
* the JSON-RPC client for communication
9596
*/
9697
CopilotSession(String sessionId, JsonRpcClient rpc) {
98+
this(sessionId, rpc, null);
99+
}
100+
101+
/**
102+
* Creates a new session with the given ID, RPC client, and workspace path.
103+
* <p>
104+
* This constructor is package-private. Sessions should be created via
105+
* {@link CopilotClient#createSession} or {@link CopilotClient#resumeSession}.
106+
*
107+
* @param sessionId
108+
* the unique session identifier
109+
* @param rpc
110+
* the JSON-RPC client for communication
111+
* @param workspacePath
112+
* the workspace path if infinite sessions are enabled
113+
*/
114+
CopilotSession(String sessionId, JsonRpcClient rpc, String workspacePath) {
97115
this.sessionId = sessionId;
98116
this.rpc = rpc;
117+
this.workspacePath = workspacePath;
99118
}
100119

101120
/**
@@ -107,6 +126,19 @@ public String getSessionId() {
107126
return sessionId;
108127
}
109128

129+
/**
130+
* Gets the path to the session workspace directory when infinite sessions are
131+
* enabled.
132+
* <p>
133+
* The workspace directory contains checkpoints/, plan.md, and files/
134+
* subdirectories.
135+
*
136+
* @return the workspace path, or {@code null} if infinite sessions are disabled
137+
*/
138+
public String getWorkspacePath() {
139+
return workspacePath;
140+
}
141+
110142
/**
111143
* Sends a simple text message to the Copilot session.
112144
* <p>

src/main/java/com/github/copilot/sdk/json/CreateSessionRequest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ public final class CreateSessionRequest {
5656
@JsonProperty("customAgents")
5757
private List<CustomAgentConfig> customAgents;
5858

59+
@JsonProperty("infiniteSessions")
60+
private InfiniteSessionConfig infiniteSessions;
61+
5962
/** Gets the model name. @return the model */
6063
public String getModel() {
6164
return model;
@@ -165,4 +168,14 @@ public List<CustomAgentConfig> getCustomAgents() {
165168
public void setCustomAgents(List<CustomAgentConfig> customAgents) {
166169
this.customAgents = customAgents;
167170
}
171+
172+
/** Gets infinite sessions config. @return the config */
173+
public InfiniteSessionConfig getInfiniteSessions() {
174+
return infiniteSessions;
175+
}
176+
177+
/** Sets infinite sessions config. @param infiniteSessions the config */
178+
public void setInfiniteSessions(InfiniteSessionConfig infiniteSessions) {
179+
this.infiniteSessions = infiniteSessions;
180+
}
168181
}

src/main/java/com/github/copilot/sdk/json/CreateSessionResponse.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,25 @@ public final class CreateSessionResponse {
88
@JsonProperty("sessionId")
99
private String sessionId;
1010

11+
@JsonProperty("workspacePath")
12+
private String workspacePath;
13+
1114
public String getSessionId() {
1215
return sessionId;
1316
}
1417
public void setSessionId(String sessionId) {
1518
this.sessionId = sessionId;
1619
}
20+
21+
/**
22+
* Gets the workspace path when infinite sessions are enabled.
23+
*
24+
* @return the workspace path, or {@code null} if infinite sessions are disabled
25+
*/
26+
public String getWorkspacePath() {
27+
return workspacePath;
28+
}
29+
public void setWorkspacePath(String workspacePath) {
30+
this.workspacePath = workspacePath;
31+
}
1732
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
*--------------------------------------------------------------------------------------------*/
4+
5+
package com.github.copilot.sdk.json;
6+
7+
import com.fasterxml.jackson.annotation.JsonInclude;
8+
import com.fasterxml.jackson.annotation.JsonProperty;
9+
10+
/**
11+
* Configuration for infinite sessions with automatic context compaction and
12+
* workspace persistence.
13+
* <p>
14+
* When enabled, sessions automatically manage context window limits through
15+
* background compaction and persist state to a workspace directory.
16+
*
17+
* <h2>Example Usage</h2>
18+
*
19+
* <pre>{@code
20+
* var infiniteConfig = new InfiniteSessionConfig().setEnabled(true).setBackgroundCompactionThreshold(0.80)
21+
* .setBufferExhaustionThreshold(0.95);
22+
*
23+
* var config = new SessionConfig().setInfiniteSessions(infiniteConfig);
24+
*
25+
* var session = client.createSession(config).get();
26+
* }</pre>
27+
*
28+
* @see SessionConfig#setInfiniteSessions(InfiniteSessionConfig)
29+
*/
30+
@JsonInclude(JsonInclude.Include.NON_NULL)
31+
public class InfiniteSessionConfig {
32+
33+
@JsonProperty("enabled")
34+
private Boolean enabled;
35+
36+
@JsonProperty("backgroundCompactionThreshold")
37+
private Double backgroundCompactionThreshold;
38+
39+
@JsonProperty("bufferExhaustionThreshold")
40+
private Double bufferExhaustionThreshold;
41+
42+
/**
43+
* Gets whether infinite sessions are enabled.
44+
*
45+
* @return {@code true} if enabled, {@code null} to use default (true)
46+
*/
47+
public Boolean getEnabled() {
48+
return enabled;
49+
}
50+
51+
/**
52+
* Sets whether infinite sessions are enabled.
53+
* <p>
54+
* Default: true
55+
*
56+
* @param enabled
57+
* {@code true} to enable infinite sessions
58+
* @return this config instance for method chaining
59+
*/
60+
public InfiniteSessionConfig setEnabled(Boolean enabled) {
61+
this.enabled = enabled;
62+
return this;
63+
}
64+
65+
/**
66+
* Gets the background compaction threshold.
67+
*
68+
* @return the threshold (0.0-1.0), or {@code null} to use default
69+
*/
70+
public Double getBackgroundCompactionThreshold() {
71+
return backgroundCompactionThreshold;
72+
}
73+
74+
/**
75+
* Sets the context utilization threshold at which background compaction starts.
76+
* <p>
77+
* Compaction runs asynchronously, allowing the session to continue processing.
78+
* Default: 0.80
79+
*
80+
* @param backgroundCompactionThreshold
81+
* the threshold (0.0-1.0)
82+
* @return this config instance for method chaining
83+
*/
84+
public InfiniteSessionConfig setBackgroundCompactionThreshold(Double backgroundCompactionThreshold) {
85+
this.backgroundCompactionThreshold = backgroundCompactionThreshold;
86+
return this;
87+
}
88+
89+
/**
90+
* Gets the buffer exhaustion threshold.
91+
*
92+
* @return the threshold (0.0-1.0), or {@code null} to use default
93+
*/
94+
public Double getBufferExhaustionThreshold() {
95+
return bufferExhaustionThreshold;
96+
}
97+
98+
/**
99+
* Sets the context utilization threshold at which the session blocks until
100+
* compaction completes.
101+
* <p>
102+
* This prevents context overflow when compaction hasn't finished in time.
103+
* Default: 0.95
104+
*
105+
* @param bufferExhaustionThreshold
106+
* the threshold (0.0-1.0)
107+
* @return this config instance for method chaining
108+
*/
109+
public InfiniteSessionConfig setBufferExhaustionThreshold(Double bufferExhaustionThreshold) {
110+
this.bufferExhaustionThreshold = bufferExhaustionThreshold;
111+
return this;
112+
}
113+
}

src/main/java/com/github/copilot/sdk/json/ResumeSessionResponse.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,25 @@ public final class ResumeSessionResponse {
88
@JsonProperty("sessionId")
99
private String sessionId;
1010

11+
@JsonProperty("workspacePath")
12+
private String workspacePath;
13+
1114
public String getSessionId() {
1215
return sessionId;
1316
}
1417
public void setSessionId(String sessionId) {
1518
this.sessionId = sessionId;
1619
}
20+
21+
/**
22+
* Gets the workspace path when infinite sessions are enabled.
23+
*
24+
* @return the workspace path, or {@code null} if infinite sessions are disabled
25+
*/
26+
public String getWorkspacePath() {
27+
return workspacePath;
28+
}
29+
public void setWorkspacePath(String workspacePath) {
30+
this.workspacePath = workspacePath;
31+
}
1732
}

src/main/java/com/github/copilot/sdk/json/SessionConfig.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public class SessionConfig {
4141
private boolean streaming;
4242
private Map<String, Object> mcpServers;
4343
private List<CustomAgentConfig> customAgents;
44+
private InfiniteSessionConfig infiniteSessions;
4445

4546
/**
4647
* Gets the custom session ID.
@@ -309,4 +310,31 @@ public SessionConfig setCustomAgents(List<CustomAgentConfig> customAgents) {
309310
this.customAgents = customAgents;
310311
return this;
311312
}
313+
314+
/**
315+
* Gets the infinite sessions configuration.
316+
*
317+
* @return the infinite sessions config
318+
*/
319+
public InfiniteSessionConfig getInfiniteSessions() {
320+
return infiniteSessions;
321+
}
322+
323+
/**
324+
* Sets the infinite session configuration for persistent workspaces and
325+
* automatic compaction.
326+
* <p>
327+
* When enabled (default), sessions automatically manage context limits and
328+
* persist state to a workspace directory. The workspace contains checkpoints/,
329+
* plan.md, and files/ subdirectories.
330+
*
331+
* @param infiniteSessions
332+
* the infinite sessions configuration
333+
* @return this config instance for method chaining
334+
* @see InfiniteSessionConfig
335+
*/
336+
public SessionConfig setInfiniteSessions(InfiniteSessionConfig infiniteSessions) {
337+
this.infiniteSessions = infiniteSessions;
338+
return this;
339+
}
312340
}

src/site/markdown/documentation.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ This document provides detailed API reference and usage examples for the Copilot
1818
- [File Attachments](#File_Attachments)
1919
- [Bring Your Own Key (BYOK)](#Bring_Your_Own_Key_.28BYOK.29)
2020
- [Permission Handling](#Permission_Handling)
21+
- [Infinite Sessions](#Infinite_Sessions)
2122
- [Error Handling](#Error_Handling)
2223

2324
## API Reference
@@ -413,6 +414,78 @@ var session = client.createSession(
413414
).get();
414415
```
415416

417+
### Infinite Sessions
418+
419+
Infinite sessions enable automatic context management for long-running conversations. When enabled (default), the session automatically manages context window limits through background compaction and persists state to a workspace directory.
420+
421+
#### How It Works
422+
423+
As conversations grow, they eventually approach the model's context window limit. Infinite sessions solve this by:
424+
425+
1. **Background Compaction**: When context utilization reaches the background threshold (default 80%), the session starts compacting older messages asynchronously while continuing to process new messages.
426+
427+
2. **Buffer Exhaustion Protection**: If context reaches the exhaustion threshold (default 95%) before compaction completes, the session blocks until compaction finishes to prevent overflow.
428+
429+
3. **Workspace Persistence**: Session state is persisted to a workspace directory containing:
430+
- `checkpoints/` - Session checkpoints for resumption
431+
- `plan.md` - Current conversation plan
432+
- `files/` - Associated files
433+
434+
#### Configuration
435+
436+
```java
437+
var infiniteConfig = new InfiniteSessionConfig()
438+
.setEnabled(true)
439+
.setBackgroundCompactionThreshold(0.80) // Start compacting at 80% utilization
440+
.setBufferExhaustionThreshold(0.95); // Block at 95% until compaction completes
441+
442+
var session = client.createSession(
443+
new SessionConfig()
444+
.setModel("gpt-5")
445+
.setInfiniteSessions(infiniteConfig)
446+
).get();
447+
```
448+
449+
#### Configuration Options
450+
451+
| Option | Default | Description |
452+
|--------|---------|-------------|
453+
| `enabled` | `true` | Whether infinite sessions are enabled |
454+
| `backgroundCompactionThreshold` | `0.80` | Context utilization (0.0-1.0) at which background compaction starts |
455+
| `bufferExhaustionThreshold` | `0.95` | Context utilization (0.0-1.0) at which the session blocks until compaction completes |
456+
457+
#### Accessing the Workspace
458+
459+
When infinite sessions are enabled, you can access the workspace path:
460+
461+
```java
462+
var session = client.createSession(
463+
new SessionConfig()
464+
.setModel("gpt-5")
465+
.setInfiniteSessions(new InfiniteSessionConfig().setEnabled(true))
466+
).get();
467+
468+
String workspacePath = session.getWorkspacePath();
469+
if (workspacePath != null) {
470+
System.out.println("Session workspace: " + workspacePath);
471+
// Access checkpoints/, plan.md, files/ subdirectories
472+
}
473+
```
474+
475+
#### Disabling Infinite Sessions
476+
477+
For short conversations where context management isn't needed:
478+
479+
```java
480+
var session = client.createSession(
481+
new SessionConfig()
482+
.setModel("gpt-5")
483+
.setInfiniteSessions(new InfiniteSessionConfig().setEnabled(false))
484+
).get();
485+
486+
// session.getWorkspacePath() will return null
487+
```
488+
416489
## Error Handling
417490

418491
```java

0 commit comments

Comments
 (0)