44
55using Microsoft . Extensions . AI ;
66using StreamJsonRpc ;
7+ using System . Collections . Concurrent ;
78using System . Text . Json ;
89using System . Text . Json . Nodes ;
910using System . Text . Json . Serialization ;
@@ -44,7 +45,7 @@ namespace GitHub.Copilot.SDK;
4445/// </example>
4546public partial class CopilotSession : IAsyncDisposable
4647{
47- private readonly HashSet < SessionEventHandler > _eventHandlers = new ( ) ;
48+ private readonly ConcurrentDictionary < SessionEventHandler , bool > _eventHandlers = new ( ) ;
4849 private readonly Dictionary < string , AIFunction > _toolHandlers = new ( ) ;
4950 private readonly JsonRpc _rpc ;
5051 private PermissionRequestHandler ? _permissionHandler ;
@@ -245,8 +246,8 @@ void Handler(SessionEvent evt)
245246 /// </example>
246247 public IDisposable On ( SessionEventHandler handler )
247248 {
248- _eventHandlers . Add ( handler ) ;
249- return new OnDisposeCall ( ( ) => _eventHandlers . Remove ( handler ) ) ;
249+ _eventHandlers . TryAdd ( handler , true ) ;
250+ return new OnDisposeCall ( ( ) => _eventHandlers . TryRemove ( handler , out _ ) ) ;
250251 }
251252
252253 /// <summary>
@@ -258,7 +259,7 @@ public IDisposable On(SessionEventHandler handler)
258259 /// </remarks>
259260 internal void DispatchEvent ( SessionEvent sessionEvent )
260261 {
261- foreach ( var handler in _eventHandlers . ToArray ( ) )
262+ foreach ( var handler in _eventHandlers . Keys )
262263 {
263264 // We allow handler exceptions to propagate so they are not lost
264265 handler ( sessionEvent ) ;
0 commit comments