@@ -47,51 +47,43 @@ public sealed class LanguageModelFailurePlugin(
4747
4848 public override string Name => nameof ( LanguageModelFailurePlugin ) ;
4949
50- public override async Task BeforeRequestAsync ( ProxyRequestArgs e , CancellationToken cancellationToken )
50+ public override Func < RequestArguments , CancellationToken , Task < PluginResponse > > ? OnRequestAsync => async ( args , cancellationToken ) =>
5151 {
52- Logger . LogTrace ( "{Method} called" , nameof ( BeforeRequestAsync ) ) ;
52+ Logger . LogTrace ( "{Method} called" , nameof ( OnRequestAsync ) ) ;
5353
54- ArgumentNullException . ThrowIfNull ( e ) ;
55-
56- if ( ! e . HasRequestUrlMatch ( UrlsToWatch ) )
57- {
58- Logger . LogRequest ( "URL not matched" , MessageType . Skipped , new LoggingContext ( e . Session ) ) ;
59- return ;
60- }
61- if ( e . ResponseState . HasBeenSet )
54+ if ( ! ProxyUtils . MatchesUrlToWatch ( UrlsToWatch , args . Request . RequestUri ) )
6255 {
63- Logger . LogRequest ( "Response already set " , MessageType . Skipped , new LoggingContext ( e . Session ) ) ;
64- return ;
56+ Logger . LogRequest ( "URL not matched " , MessageType . Skipped , args . Request , args . RequestId ) ;
57+ return PluginResponse . Continue ( ) ;
6558 }
6659
67- var request = e . Session . HttpClient . Request ;
68- if ( request . Method is null ||
69- ! request . Method . Equals ( "POST" , StringComparison . OrdinalIgnoreCase ) ||
70- ! request . HasBody )
60+ if ( args . Request . Method != HttpMethod . Post || args . Request . Content == null )
7161 {
72- Logger . LogRequest ( "Request is not a POST request with a body" , MessageType . Skipped , new ( e . Session ) ) ;
73- return ;
62+ Logger . LogRequest ( "Request is not a POST request with a body" , MessageType . Skipped , args . Request , args . RequestId ) ;
63+ return PluginResponse . Continue ( ) ;
7464 }
7565
76- if ( ! TryGetOpenAIRequest ( request . BodyString , out var openAiRequest ) )
66+ var requestBody = await args . Request . Content . ReadAsStringAsync ( cancellationToken ) ;
67+ if ( ! TryGetOpenAIRequest ( requestBody , out var openAiRequest ) )
7768 {
78- Logger . LogRequest ( "Skipping non-OpenAI request" , MessageType . Skipped , new ( e . Session ) ) ;
79- return ;
69+ Logger . LogRequest ( "Skipping non-OpenAI request" , MessageType . Skipped , args . Request , args . RequestId ) ;
70+ return PluginResponse . Continue ( ) ;
8071 }
8172
8273 var ( faultName , faultPrompt ) = GetFault ( ) ;
8374 if ( faultPrompt is null )
8475 {
8576 Logger . LogError ( "Failed to get fault prompt. Passing request as-is." ) ;
86- return ;
77+ return PluginResponse . Continue ( ) ;
8778 }
8879
80+ string modifiedRequestBody ;
8981 if ( openAiRequest is OpenAICompletionRequest completionRequest )
9082 {
9183 completionRequest . Prompt += "\n \n " + faultPrompt ;
9284 Logger . LogDebug ( "Modified completion request prompt: {Prompt}" , completionRequest . Prompt ) ;
93- Logger . LogRequest ( $ "Simulating fault { faultName } ", MessageType . Chaos , new ( e . Session ) ) ;
94- e . Session . SetRequestBodyString ( JsonSerializer . Serialize ( completionRequest , ProxyUtils . JsonSerializerOptions ) ) ;
85+ Logger . LogRequest ( $ "Simulating fault { faultName } ", MessageType . Chaos , args . Request , args . RequestId ) ;
86+ modifiedRequestBody = JsonSerializer . Serialize ( completionRequest , ProxyUtils . JsonSerializerOptions ) ;
9587 }
9688 else if ( openAiRequest is OpenAIChatCompletionRequest chatRequest )
9789 {
@@ -113,18 +105,43 @@ public override async Task BeforeRequestAsync(ProxyRequestArgs e, CancellationTo
113105 } ;
114106
115107 Logger . LogDebug ( "Added fault prompt to messages: {Prompt}" , faultPrompt ) ;
116- Logger . LogRequest ( $ "Simulating fault { faultName } ", MessageType . Chaos , new ( e . Session ) ) ;
117- e . Session . SetRequestBodyString ( JsonSerializer . Serialize ( newRequest , ProxyUtils . JsonSerializerOptions ) ) ;
108+ Logger . LogRequest ( $ "Simulating fault { faultName } ", MessageType . Chaos , args . Request , args . RequestId ) ;
109+ modifiedRequestBody = JsonSerializer . Serialize ( newRequest , ProxyUtils . JsonSerializerOptions ) ;
118110 }
119111 else
120112 {
121113 Logger . LogDebug ( "Unknown OpenAI request type. Passing request as-is." ) ;
114+ return PluginResponse . Continue ( ) ;
122115 }
123116
124- await Task . CompletedTask ;
117+ // Create new request with modified body
118+ var modifiedRequest = new HttpRequestMessage ( args . Request . Method , args . Request . RequestUri )
119+ {
120+ Content = new StringContent ( modifiedRequestBody , System . Text . Encoding . UTF8 , "application/json" )
121+ } ;
122+
123+ // Copy headers from original request
124+ foreach ( var header in args . Request . Headers )
125+ {
126+ _ = modifiedRequest . Headers . TryAddWithoutValidation ( header . Key , header . Value ) ;
127+ }
125128
126- Logger . LogTrace ( "Left {Name}" , nameof ( BeforeRequestAsync ) ) ;
127- }
129+ // Copy content headers if they exist
130+ if ( args . Request . Content ? . Headers != null )
131+ {
132+ foreach ( var header in args . Request . Content . Headers )
133+ {
134+ if ( ! header . Key . Equals ( "Content-Type" , StringComparison . OrdinalIgnoreCase ) &&
135+ ! header . Key . Equals ( "Content-Length" , StringComparison . OrdinalIgnoreCase ) )
136+ {
137+ _ = modifiedRequest . Content . Headers . TryAddWithoutValidation ( header . Key , header . Value ) ;
138+ }
139+ }
140+ }
141+
142+ Logger . LogTrace ( "Left {Name}" , nameof ( OnRequestAsync ) ) ;
143+ return PluginResponse . Continue ( modifiedRequest ) ;
144+ } ;
128145
129146 private bool TryGetOpenAIRequest ( string content , out OpenAIRequest ? request )
130147 {
0 commit comments