@@ -41,20 +41,40 @@ public enum CopilotRequestTransport
4141[ Experimental ( Diagnostics . Experimental ) ]
4242public sealed class CopilotRequestContext
4343{
44+ /// <summary>
45+ /// Creates an instance of <see cref="CopilotRequestContext"/> by copying the values from another instance.
46+ /// </summary>
47+ /// <param name="original">A <see cref="CopilotRequestContext"/> instance to copy values from.</param>
48+ public CopilotRequestContext ( CopilotRequestContext original )
49+ : this ( original . RequestId , original . Url , original . Headers )
50+ {
51+ SessionId = original . SessionId ;
52+ Transport = original . Transport ;
53+ CancellationToken = original . CancellationToken ;
54+ WebSocketResponse = original . WebSocketResponse ;
55+ }
56+
57+ internal CopilotRequestContext ( string requestId , string url , IReadOnlyDictionary < string , IReadOnlyList < string > > headers )
58+ {
59+ RequestId = requestId ;
60+ Url = url ;
61+ Headers = headers ;
62+ }
63+
4464 /// <summary>Opaque runtime-minted id, stable across the request lifecycle.</summary>
45- public required string RequestId { get ; init ; }
65+ public string RequestId { get ; init ; }
4666
4767 /// <summary>Runtime session id that triggered the request, if any.</summary>
4868 public string ? SessionId { get ; init ; }
4969
5070 /// <summary>Transport the runtime would otherwise use.</summary>
5171 public CopilotRequestTransport Transport { get ; init ; }
5272
53- /// <summary>Original request URL.</summary>
54- public required string Url { get ; init ; }
73+ /// <summary>Request URL.</summary>
74+ public string Url { get ; init ; }
5575
56- /// <summary>Original request headers.</summary>
57- public required IReadOnlyDictionary < string , IReadOnlyList < string > > Headers { get ; init ; }
76+ /// <summary>Request headers.</summary>
77+ public IReadOnlyDictionary < string , IReadOnlyList < string > > Headers { get ; init ; }
5878
5979 /// <summary>
6080 /// Cancelled when the runtime aborts this in-flight request. Subclasses that
@@ -199,25 +219,17 @@ public virtual async ValueTask DisposeAsync()
199219[ Experimental ( Diagnostics . Experimental ) ]
200220public class CopilotWebSocketForwarder : CopilotWebSocketHandler
201221{
202- private readonly string _url ;
203- private readonly IReadOnlyDictionary < string , IReadOnlyList < string > > _headers ;
204222 private WebSocket ? _upstream ;
205223 private CancellationTokenSource ? _pumpCts ;
206224 private Task ? _responsePump ;
207225
208226 /// <summary>
209227 /// Initializes a forwarding handler that will open the upstream socket on
210- /// demand using the supplied URL/headers (or the values from
211- /// <paramref name="context"/> when omitted).
228+ /// demand using the supplied URL/headers from <paramref name="context"/>.
212229 /// </summary>
213- public CopilotWebSocketForwarder (
214- CopilotRequestContext context ,
215- string ? url = null ,
216- IReadOnlyDictionary < string , IReadOnlyList < string > > ? headers = null )
230+ public CopilotWebSocketForwarder ( CopilotRequestContext context )
217231 : base ( context )
218232 {
219- _url = url ?? context . Url ;
220- _headers = headers ?? context . Headers ;
221233 }
222234
223235 /// <summary>
@@ -231,7 +243,7 @@ internal override async Task OpenAsync()
231243 }
232244
233245 var socket = new ClientWebSocket ( ) ;
234- foreach ( var ( name , values ) in _headers )
246+ foreach ( var ( name , values ) in Context . Headers )
235247 {
236248 if ( LlmInferenceHeaders . Forbidden . Contains ( name ) )
237249 {
@@ -248,7 +260,7 @@ internal override async Task OpenAsync()
248260 }
249261 }
250262
251- await socket . ConnectAsync ( ToWebSocketUri ( _url ) , Context . CancellationToken ) . ConfigureAwait ( false ) ;
263+ await socket . ConnectAsync ( ToWebSocketUri ( Context . Url ) , Context . CancellationToken ) . ConfigureAwait ( false ) ;
252264 _upstream = socket ;
253265 _pumpCts = CancellationTokenSource . CreateLinkedTokenSource ( Context . CancellationToken ) ;
254266
@@ -855,13 +867,10 @@ public Task<LlmInferenceHttpRequestStartResult> HttpRequestStartAsync(LlmInferen
855867 // dropping those frames and hanging the body drain.
856868 var exchange = _pending . GetOrAdd ( request . RequestId , id => new LlmInferenceExchange ( id , _getServerRpc ) ) ;
857869 exchange . Method = request . Method ;
858- exchange . Context = new CopilotRequestContext
870+ exchange . Context = new CopilotRequestContext ( request . RequestId , request . Url , ToReadOnlyHeaders ( request . Headers ) )
859871 {
860- RequestId = request . RequestId ,
861872 SessionId = request . SessionId ,
862873 Transport = transport ,
863- Url = request . Url ,
864- Headers = ToReadOnlyHeaders ( request . Headers ) ,
865874 CancellationToken = exchange . Abort . Token ,
866875 } ;
867876
0 commit comments