From 4c2fc3bc92e9d84e38c4536a97f5c46f843f4420 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Feb 2026 17:55:07 +0000 Subject: [PATCH 1/4] Initial plan From 9cb7dd41577a44e6d82fd8e12daf1113e5a37213 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Feb 2026 18:00:16 +0000 Subject: [PATCH 2/4] Fix session.shutdown event timing by adding delay in destroy() Co-authored-by: SteveSandersonMS <1101362+SteveSandersonMS@users.noreply.github.com> --- nodejs/examples/test-shutdown-event.ts | 42 ++++++++++++++++++++++++++ nodejs/src/session.ts | 6 ++++ 2 files changed, 48 insertions(+) create mode 100644 nodejs/examples/test-shutdown-event.ts diff --git a/nodejs/examples/test-shutdown-event.ts b/nodejs/examples/test-shutdown-event.ts new file mode 100644 index 000000000..9ab3c0e85 --- /dev/null +++ b/nodejs/examples/test-shutdown-event.ts @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { CopilotClient } from "../src/index.js"; + +console.log("šŸš€ Testing session.shutdown event\n"); + +// Create client +const client = new CopilotClient({ logLevel: "info" }); +const session = await client.createSession(); +console.log(`āœ… Session created: ${session.sessionId}\n`); + +// Track if we receive the shutdown event +let shutdownEventReceived = false; + +// Listen to all events +session.on((event) => { + console.log(`šŸ“¢ Event [${event.type}]`); + if (event.type === "session.shutdown") { + shutdownEventReceived = true; + console.log("āœ… SHUTDOWN EVENT RECEIVED!"); + console.log(" Data:", JSON.stringify(event.data, null, 2)); + } +}); + +// Send a simple message +console.log("šŸ’¬ Sending message..."); +const result = await session.sendAndWait({ prompt: "What is 2+2?" }); +console.log("šŸ“ Response:", result?.data.content); + +// Clean up +console.log("\nšŸ”„ Destroying session..."); +await session.destroy(); + +// Give a bit more time for any delayed events +await new Promise(resolve => setTimeout(resolve, 200)); + +console.log("\n" + (shutdownEventReceived ? "āœ… SUCCESS: session.shutdown event was received!" : "āŒ FAILURE: session.shutdown event was NOT received!")); + +await client.stop(); +console.log("\nāœ… Done!"); diff --git a/nodejs/src/session.ts b/nodejs/src/session.ts index 04525d2bb..828dcf90d 100644 --- a/nodejs/src/session.ts +++ b/nodejs/src/session.ts @@ -518,6 +518,12 @@ export class CopilotSession { await this.connection.sendRequest("session.destroy", { sessionId: this.sessionId, }); + + // Wait briefly for any final notifications (e.g., session.shutdown) + // to arrive before clearing handlers. The CLI may send these after + // the RPC response. + await new Promise((resolve) => setTimeout(resolve, 100)); + this.eventHandlers.clear(); this.typedEventHandlers.clear(); this.toolHandlers.clear(); From 4b0ad44496496e050037bca43e4bf5fb8757b738 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Feb 2026 18:02:12 +0000 Subject: [PATCH 3/4] Fix session.shutdown event timing in Python, Go, and .NET SDKs Co-authored-by: SteveSandersonMS <1101362+SteveSandersonMS@users.noreply.github.com> --- dotnet/src/Session.cs | 5 +++++ go/session.go | 5 +++++ python/copilot/session.py | 6 ++++++ 3 files changed, 16 insertions(+) diff --git a/dotnet/src/Session.cs b/dotnet/src/Session.cs index 34f4d02d5..00c410cbc 100644 --- a/dotnet/src/Session.cs +++ b/dotnet/src/Session.cs @@ -580,6 +580,11 @@ await InvokeRpcAsync( // Connection is broken or closed } + // Wait briefly for any final notifications (e.g., session.shutdown) + // to arrive before clearing handlers. The CLI may send these after + // the RPC response. + await Task.Delay(100); + _eventHandlers.Clear(); _toolHandlers.Clear(); diff --git a/go/session.go b/go/session.go index ce1a3eff0..7012fb309 100644 --- a/go/session.go +++ b/go/session.go @@ -531,6 +531,11 @@ func (s *Session) Destroy() error { return fmt.Errorf("failed to destroy session: %w", err) } + // Wait briefly for any final notifications (e.g., session.shutdown) + // to arrive before clearing handlers. The CLI may send these after + // the RPC response. + time.Sleep(100 * time.Millisecond) + // Clear handlers s.handlerMutex.Lock() s.handlers = nil diff --git a/python/copilot/session.py b/python/copilot/session.py index d7bd1a3f4..066975aa0 100644 --- a/python/copilot/session.py +++ b/python/copilot/session.py @@ -487,6 +487,12 @@ async def destroy(self) -> None: >>> await session.destroy() """ await self._client.request("session.destroy", {"sessionId": self.session_id}) + + # Wait briefly for any final notifications (e.g., session.shutdown) + # to arrive before clearing handlers. The CLI may send these after + # the RPC response. + await asyncio.sleep(0.1) + with self._event_handlers_lock: self._event_handlers.clear() with self._tool_handlers_lock: From d7fb67cdee7ff02efe70b84c33553d85835aef3c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Feb 2026 18:07:26 +0000 Subject: [PATCH 4/4] Format code with prettier and black Co-authored-by: SteveSandersonMS <1101362+SteveSandersonMS@users.noreply.github.com> --- nodejs/src/session.ts | 4 ++-- python/copilot/session.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nodejs/src/session.ts b/nodejs/src/session.ts index 828dcf90d..ca2d7a253 100644 --- a/nodejs/src/session.ts +++ b/nodejs/src/session.ts @@ -518,12 +518,12 @@ export class CopilotSession { await this.connection.sendRequest("session.destroy", { sessionId: this.sessionId, }); - + // Wait briefly for any final notifications (e.g., session.shutdown) // to arrive before clearing handlers. The CLI may send these after // the RPC response. await new Promise((resolve) => setTimeout(resolve, 100)); - + this.eventHandlers.clear(); this.typedEventHandlers.clear(); this.toolHandlers.clear(); diff --git a/python/copilot/session.py b/python/copilot/session.py index 066975aa0..4cc5210fd 100644 --- a/python/copilot/session.py +++ b/python/copilot/session.py @@ -487,12 +487,12 @@ async def destroy(self) -> None: >>> await session.destroy() """ await self._client.request("session.destroy", {"sessionId": self.session_id}) - + # Wait briefly for any final notifications (e.g., session.shutdown) # to arrive before clearing handlers. The CLI may send these after # the RPC response. await asyncio.sleep(0.1) - + with self._event_handlers_lock: self._event_handlers.clear() with self._tool_handlers_lock: