Skip to content

Commit 4e1499d

Browse files
patnikoCopilot
andauthored
docs: clarify session destroy vs delete semantics (#599)
* docs: clarify session destroy vs delete semantics across all SDKs Clarify the distinction between destroy() (closes session, releases in-memory resources, preserves disk state for resumption) and deleteSession() (permanently removes all data from disk). Update doc comments across all four SDK languages (Go, Node.js, Python, .NET) and the session persistence guide to make the behavioral difference explicit and help users choose the right method. Fixes #526 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat: add disconnect() method, deprecate destroy() across all SDKs Add disconnect() as the preferred method for closing sessions across all four SDK languages, marking destroy() as deprecated: - Node.js: disconnect() + Symbol.asyncDispose support, destroy() delegates - Python: disconnect() + __aenter__/__aexit__ context manager, destroy() emits DeprecationWarning - Go: Disconnect() method, Destroy() marked with Deprecated godoc tag - .NET: DisconnectAsync() method, DisposeAsync() delegates to it Update all samples, READMEs, and documentation guides to use the new disconnect() terminology. Internal stop() methods now call disconnect(). Resolves PR #599 comments: - Rename destroy → disconnect for clarity - Define IDisposable behavior in .NET (DisposeAsync delegates to DisconnectAsync) - Add idiomatic cleanup patterns (async context managers, Symbol.asyncDispose) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore: update all tests, scenarios, and docs to use disconnect() Migrate all test scenarios, e2e tests, READMEs, and documentation references from destroy()/Destroy() to disconnect()/Disconnect(). - 90 test scenario files across Go/Python/TypeScript/C# - 15 Node.js e2e test files - 8 Python e2e test files - 3 Go e2e test files - 1 .NET test file - READMEs and compatibility docs updated with new API reference - Agent docs updated with new method names - Reconnect scenario log messages updated to 'disconnected' Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: rename snapshot to match updated test name The hooks_extended test 'should invoke onSessionEnd hook when session is destroyed' was renamed to '...disconnected', but the snapshot YAML file wasn't renamed to match, causing CI to fail with 'No cached response'. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * dotnet: remove DisconnectAsync, keep only DisposeAsync Address review feedback from SteveSandersonMS: for .NET, the standard IAsyncDisposable pattern (DisposeAsync) is sufficient on its own without a duplicate DisconnectAsync method. Moves the disconnect implementation directly into DisposeAsync and removes the separate DisconnectAsync method. Updates all references in Client.cs and README.md accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 4246289 commit 4e1499d

File tree

150 files changed

+508
-350
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

150 files changed

+508
-350
lines changed

.github/agents/docs-maintenance.agent.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ cat nodejs/src/types.ts | grep -A 10 "export interface ExportSessionOptions"
344344
**Must match:**
345345
- `CopilotClient` constructor options: `cliPath`, `cliUrl`, `useStdio`, `port`, `logLevel`, `autoStart`, `autoRestart`, `env`, `githubToken`, `useLoggedInUser`
346346
- `createSession()` config: `model`, `tools`, `hooks`, `systemMessage`, `mcpServers`, `availableTools`, `excludedTools`, `streaming`, `reasoningEffort`, `provider`, `infiniteSessions`, `customAgents`, `workingDirectory`
347-
- `CopilotSession` methods: `send()`, `sendAndWait()`, `getMessages()`, `destroy()`, `abort()`, `on()`, `once()`, `off()`
347+
- `CopilotSession` methods: `send()`, `sendAndWait()`, `getMessages()`, `disconnect()`, `abort()`, `on()`, `once()`, `off()`
348348
- Hook names: `onPreToolUse`, `onPostToolUse`, `onUserPromptSubmitted`, `onSessionStart`, `onSessionEnd`, `onErrorOccurred`
349349

350350
#### Python Validation
@@ -362,7 +362,7 @@ cat python/copilot/types.py | grep -A 15 "class SessionHooks"
362362
**Must match (snake_case):**
363363
- `CopilotClient` options: `cli_path`, `cli_url`, `use_stdio`, `port`, `log_level`, `auto_start`, `auto_restart`, `env`, `github_token`, `use_logged_in_user`
364364
- `create_session()` config keys: `model`, `tools`, `hooks`, `system_message`, `mcp_servers`, `available_tools`, `excluded_tools`, `streaming`, `reasoning_effort`, `provider`, `infinite_sessions`, `custom_agents`, `working_directory`
365-
- `CopilotSession` methods: `send()`, `send_and_wait()`, `get_messages()`, `destroy()`, `abort()`, `export_session()`
365+
- `CopilotSession` methods: `send()`, `send_and_wait()`, `get_messages()`, `disconnect()`, `abort()`, `export_session()`
366366
- Hook names: `on_pre_tool_use`, `on_post_tool_use`, `on_user_prompt_submitted`, `on_session_start`, `on_session_end`, `on_error_occurred`
367367

368368
#### Go Validation
@@ -380,7 +380,7 @@ cat go/types.go | grep -A 15 "type SessionHooks struct"
380380
**Must match (PascalCase for exported):**
381381
- `ClientOptions` fields: `CLIPath`, `CLIUrl`, `UseStdio`, `Port`, `LogLevel`, `AutoStart`, `AutoRestart`, `Env`, `GithubToken`, `UseLoggedInUser`
382382
- `SessionConfig` fields: `Model`, `Tools`, `Hooks`, `SystemMessage`, `MCPServers`, `AvailableTools`, `ExcludedTools`, `Streaming`, `ReasoningEffort`, `Provider`, `InfiniteSessions`, `CustomAgents`, `WorkingDirectory`
383-
- `Session` methods: `Send()`, `SendAndWait()`, `GetMessages()`, `Destroy()`, `Abort()`, `ExportSession()`
383+
- `Session` methods: `Send()`, `SendAndWait()`, `GetMessages()`, `Disconnect()`, `Abort()`, `ExportSession()`
384384
- Hook fields: `OnPreToolUse`, `OnPostToolUse`, `OnUserPromptSubmitted`, `OnSessionStart`, `OnSessionEnd`, `OnErrorOccurred`
385385

386386
#### .NET Validation

docs/auth/byok.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ async def main():
5454
await session.send({"prompt": "What is 2+2?"})
5555
await done.wait()
5656

57-
await session.destroy()
57+
await session.disconnect()
5858
await client.stop()
5959

6060
asyncio.run(main())

docs/compatibility.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ The Copilot SDK communicates with the CLI via JSON-RPC protocol. Features must b
1515
| **Session Management** | | |
1616
| Create session | `createSession()` | Full config support |
1717
| Resume session | `resumeSession()` | With infinite session workspaces |
18-
| Destroy session | `destroy()` | Clean up resources |
18+
| Disconnect session | `disconnect()` | Release in-memory resources |
19+
| Destroy session *(deprecated)* | `destroy()` | Use `disconnect()` instead |
1920
| Delete session | `deleteSession()` | Remove from storage |
2021
| List sessions | `listSessions()` | All stored sessions |
2122
| Get last session | `getLastSessionId()` | For quick resume |

docs/debugging.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,9 @@ var client = new CopilotClient(new CopilotClientOptions
248248

249249
**Solution:**
250250

251-
1. Ensure you're not calling methods after `destroy()`:
251+
1. Ensure you're not calling methods after `disconnect()`:
252252
```typescript
253-
await session.destroy();
253+
await session.disconnect();
254254
// Don't use session after this!
255255
```
256256

docs/guides/session-persistence.md

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -325,24 +325,46 @@ async function cleanupExpiredSessions(maxAgeMs: number) {
325325
await cleanupExpiredSessions(24 * 60 * 60 * 1000);
326326
```
327327

328-
### Explicit Session Destruction
328+
### Disconnecting from a Session (`disconnect`)
329329

330-
When a task completes, destroy the session explicitly rather than waiting for timeouts:
330+
When a task completes, disconnect from the session explicitly rather than waiting for timeouts. This releases in-memory resources but **preserves session data on disk**, so the session can still be resumed later:
331331

332332
```typescript
333333
try {
334334
// Do work...
335335
await session.sendAndWait({ prompt: "Complete the task" });
336336

337-
// Task complete - clean up
338-
await session.destroy();
337+
// Task complete — release in-memory resources (session can be resumed later)
338+
await session.disconnect();
339339
} catch (error) {
340340
// Clean up even on error
341-
await session.destroy();
341+
await session.disconnect();
342342
throw error;
343343
}
344344
```
345345

346+
Each SDK also provides idiomatic automatic cleanup patterns:
347+
348+
| Language | Pattern | Example |
349+
|----------|---------|---------|
350+
| **TypeScript** | `Symbol.asyncDispose` | `await using session = await client.createSession(config);` |
351+
| **Python** | `async with` context manager | `async with await client.create_session(config) as session:` |
352+
| **C#** | `IAsyncDisposable` | `await using var session = await client.CreateSessionAsync(config);` |
353+
| **Go** | `defer` | `defer session.Disconnect()` |
354+
355+
> **Note:** `destroy()` is deprecated in favor of `disconnect()`. Existing code using `destroy()` will continue to work but should be migrated.
356+
357+
### Permanently Deleting a Session (`deleteSession`)
358+
359+
To permanently remove a session and all its data from disk (conversation history, planning state, artifacts), use `deleteSession`. This is irreversible — the session **cannot** be resumed after deletion:
360+
361+
```typescript
362+
// Permanently remove session data
363+
await client.deleteSession("user-123-task-456");
364+
```
365+
366+
> **`disconnect()` vs `deleteSession()`:** `disconnect()` releases in-memory resources but keeps session data on disk for later resumption. `deleteSession()` permanently removes everything, including files on disk.
367+
346368
## Automatic Cleanup: Idle Timeout
347369

348370
The CLI has a built-in 30-minute idle timeout. Sessions without activity are automatically cleaned up:
@@ -526,8 +548,8 @@ await withSessionLock("user-123-task-456", async () => {
526548
| **Resume session** | `client.resumeSession(sessionId)` |
527549
| **BYOK resume** | Re-provide `provider` config |
528550
| **List sessions** | `client.listSessions(filter?)` |
529-
| **Delete session** | `client.deleteSession(sessionId)` |
530-
| **Destroy active session** | `session.destroy()` |
551+
| **Disconnect from active session** | `session.disconnect()` — releases in-memory resources; session data on disk is preserved for resumption |
552+
| **Delete session permanently** | `client.deleteSession(sessionId)` — permanently removes all session data from disk; cannot be resumed |
531553
| **Containerized deployment** | Mount `~/.copilot/session-state/` to persistent storage |
532554

533555
## Next Steps

docs/guides/setup/azure-managed-identity.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ class ManagedIdentityCopilotAgent:
118118
session = await self.client.create_session(config)
119119

120120
response = await session.send_and_wait({"prompt": prompt})
121-
await session.destroy()
121+
await session.disconnect()
122122

123123
return response.data.content if response else ""
124124
```

docs/guides/setup/backend-services.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ async function processJob(job: Job) {
319319
});
320320

321321
await saveResult(job.id, response?.data.content);
322-
await session.destroy(); // Clean up after job completes
322+
await session.disconnect(); // Clean up after job completes
323323
}
324324
```
325325

docs/guides/setup/scaling.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -412,8 +412,8 @@ class SessionManager {
412412
private async evictOldestSession(): Promise<void> {
413413
const [oldestId] = this.activeSessions.keys();
414414
const session = this.activeSessions.get(oldestId)!;
415-
// Session state is persisted automatically — safe to destroy
416-
await session.destroy();
415+
// Session state is persisted automatically — safe to disconnect
416+
await session.disconnect();
417417
this.activeSessions.delete(oldestId);
418418
}
419419
}
@@ -457,7 +457,7 @@ app.post("/api/analyze", async (req, res) => {
457457
});
458458
res.json({ result: response?.data.content });
459459
} finally {
460-
await session.destroy(); // Clean up immediately
460+
await session.disconnect(); // Clean up immediately
461461
}
462462
});
463463
```

docs/mcp/overview.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ func main() {
132132
if err != nil {
133133
log.Fatal(err)
134134
}
135-
defer session.Destroy()
135+
defer session.Disconnect()
136136

137137
// Use the session...
138138
}
@@ -191,7 +191,7 @@ async function main() {
191191

192192
console.log("Response:", result?.data?.content);
193193

194-
await session.destroy();
194+
await session.disconnect();
195195
await client.stop();
196196
}
197197

dotnet/README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,17 @@ Get all events/messages from this session.
219219

220220
##### `DisposeAsync(): ValueTask`
221221

222-
Dispose the session and free resources.
222+
Close the session and release in-memory resources. Session data on disk is preserved — the conversation can be resumed later via `ResumeSessionAsync()`. To permanently delete session data, use `client.DeleteSessionAsync()`.
223+
224+
```csharp
225+
// Preferred: automatic cleanup via await using
226+
await using var session = await client.CreateSessionAsync(config);
227+
// session is automatically disposed when leaving scope
228+
229+
// Alternative: explicit dispose
230+
var session2 = await client.CreateSessionAsync(config);
231+
await session2.DisposeAsync();
232+
```
223233

224234
---
225235

0 commit comments

Comments
 (0)