Skip to content

Commit 7c3c0e6

Browse files
patnikoCopilot
andcommitted
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>
1 parent 7e9bf9d commit 7c3c0e6

File tree

3 files changed

+18
-48
lines changed

3 files changed

+18
-48
lines changed

dotnet/README.md

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -217,22 +217,18 @@ Abort the currently processing message in this session.
217217

218218
Get all events/messages from this session.
219219

220-
##### `DisconnectAsync(CancellationToken cancellationToken = default): Task`
221-
222-
Disconnect 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-
224220
##### `DisposeAsync(): ValueTask`
225221

226-
Calls `DisconnectAsync()`. Enables the `await using` pattern for automatic cleanup:
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()`.
227223

228224
```csharp
229225
// Preferred: automatic cleanup via await using
230226
await using var session = await client.CreateSessionAsync(config);
231-
// session is automatically disconnected when leaving scope
227+
// session is automatically disposed when leaving scope
232228
233-
// Alternative: explicit disconnect
229+
// Alternative: explicit dispose
234230
var session2 = await client.CreateSessionAsync(config);
235-
await session2.DisconnectAsync();
231+
await session2.DisposeAsync();
236232
```
237233

238234
---

dotnet/src/Client.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,11 +243,11 @@ public async Task StopAsync()
243243
{
244244
try
245245
{
246-
await session.DisconnectAsync();
246+
await session.DisposeAsync();
247247
}
248248
catch (Exception ex)
249249
{
250-
errors.Add(new Exception($"Failed to disconnect session {session.SessionId}: {ex.Message}", ex));
250+
errors.Add(new Exception($"Failed to dispose session {session.SessionId}: {ex.Message}", ex));
251251
}
252252
}
253253

@@ -669,7 +669,7 @@ public async Task<List<ModelInfo>> ListModelsAsync(CancellationToken cancellatio
669669
/// <returns>A task that represents the asynchronous delete operation.</returns>
670670
/// <exception cref="InvalidOperationException">Thrown when the session does not exist or deletion fails.</exception>
671671
/// <remarks>
672-
/// Unlike <see cref="CopilotSession.DisconnectAsync"/>, which only releases in-memory
672+
/// Unlike <see cref="CopilotSession.DisposeAsync"/>, which only releases in-memory
673673
/// resources and preserves session data for later resumption, this method is
674674
/// irreversible. The session cannot be resumed after deletion.
675675
/// </remarks>

dotnet/src/Session.cs

Lines changed: 11 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ namespace GitHub.Copilot.SDK;
2626
/// </para>
2727
/// <para>
2828
/// <see cref="CopilotSession"/> implements <see cref="IAsyncDisposable"/>. Use the
29-
/// <c>await using</c> pattern for automatic cleanup, or call <see cref="DisconnectAsync"/>
29+
/// <c>await using</c> pattern for automatic cleanup, or call <see cref="DisposeAsync"/>
3030
/// explicitly. Disposing a session releases in-memory resources but preserves session data
3131
/// on disk — the conversation can be resumed later via
3232
/// <see cref="CopilotClient.ResumeSessionAsync"/>. To permanently delete session data,
@@ -530,11 +530,10 @@ public async Task SetModelAsync(string model, CancellationToken cancellationToke
530530
}
531531

532532
/// <summary>
533-
/// Disconnects this session and releases all in-memory resources (event handlers,
533+
/// Closes this session and releases all in-memory resources (event handlers,
534534
/// tool handlers, permission handlers).
535535
/// </summary>
536-
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the operation.</param>
537-
/// <returns>A task representing the disconnect operation.</returns>
536+
/// <returns>A task representing the dispose operation.</returns>
538537
/// <remarks>
539538
/// <para>
540539
/// Session state on disk (conversation history, planning state, artifacts) is
@@ -549,14 +548,16 @@ public async Task SetModelAsync(string model, CancellationToken cancellationToke
549548
/// </remarks>
550549
/// <example>
551550
/// <code>
552-
/// // Disconnect when done — session can still be resumed later
553-
/// await session.DisconnectAsync();
554-
///
555-
/// // Or use 'await using' for automatic disconnection
551+
/// // Using 'await using' for automatic disposal — session can still be resumed later
556552
/// await using var session = await client.CreateSessionAsync(new() { OnPermissionRequest = PermissionHandler.ApproveAll });
553+
///
554+
/// // Or manually dispose
555+
/// var session2 = await client.CreateSessionAsync(new() { OnPermissionRequest = PermissionHandler.ApproveAll });
556+
/// // ... use the session ...
557+
/// await session2.DisposeAsync();
557558
/// </code>
558559
/// </example>
559-
public async Task DisconnectAsync(CancellationToken cancellationToken = default)
560+
public async ValueTask DisposeAsync()
560561
{
561562
if (Interlocked.Exchange(ref _isDisposed, 1) == 1)
562563
{
@@ -566,7 +567,7 @@ public async Task DisconnectAsync(CancellationToken cancellationToken = default)
566567
try
567568
{
568569
await InvokeRpcAsync<object>(
569-
"session.destroy", [new SessionDestroyRequest() { SessionId = SessionId }], cancellationToken);
570+
"session.destroy", [new SessionDestroyRequest() { SessionId = SessionId }], CancellationToken.None);
570571
}
571572
catch (ObjectDisposedException)
572573
{
@@ -583,33 +584,6 @@ await InvokeRpcAsync<object>(
583584
_permissionHandler = null;
584585
}
585586

586-
/// <summary>
587-
/// Disposes the <see cref="CopilotSession"/> by disconnecting and releasing all resources.
588-
/// </summary>
589-
/// <returns>A task representing the dispose operation.</returns>
590-
/// <remarks>
591-
/// <para>
592-
/// This method calls <see cref="DisconnectAsync"/> to perform cleanup. It is the
593-
/// implementation of <see cref="IAsyncDisposable"/> and enables the
594-
/// <c>await using</c> pattern for automatic resource management.
595-
/// </para>
596-
/// </remarks>
597-
/// <example>
598-
/// <code>
599-
/// // Using 'await using' for automatic disposal — session can still be resumed later
600-
/// await using var session = await client.CreateSessionAsync(new() { OnPermissionRequest = PermissionHandler.ApproveAll });
601-
///
602-
/// // Or manually dispose
603-
/// var session2 = await client.CreateSessionAsync(new() { OnPermissionRequest = PermissionHandler.ApproveAll });
604-
/// // ... use the session ...
605-
/// await session2.DisposeAsync();
606-
/// </code>
607-
/// </example>
608-
public async ValueTask DisposeAsync()
609-
{
610-
await DisconnectAsync();
611-
}
612-
613587
internal record SendMessageRequest
614588
{
615589
public string SessionId { get; init; } = string.Empty;

0 commit comments

Comments
 (0)