11using System . ClientModel . Primitives ;
22using System . Text . Json ;
3- using System . Text . Json . Nodes ;
43
54namespace Devlooped . Extensions . AI ;
65
76public static class PipelineTestOutput
87{
9- /// <summary>
10- /// Sets a <see cref="ClientPipelineOptions.Transport"/> that renders HTTP messages to the
11- /// console using Spectre.Console rich JSON formatting, but only if the console is interactive.
12- /// </summary>
13- /// <typeparam name="TOptions">The options type to configure for HTTP logging.</typeparam>
14- /// <param name="pipelineOptions">The options instance to configure.</param>
15- /// <param name="output">The test output helper to write to.</param>
16- /// <param name="onRequest">A callback to process the <see cref="JsonNode"/> that was sent.</param>
17- /// <param name="onResponse">A callback to process the <see cref="JsonNode"/> that was received.</param>
18- /// <remarks>
19- /// NOTE: this is the lowst-level logging after all chat pipeline processing has been done.
20- /// <para>
21- /// If the options already provide a transport, it will be wrapped with the console
22- /// logging transport to minimize the impact on existing configurations.
23- /// </para>
24- /// </remarks>
25- public static TOptions WriteTo < TOptions > ( this TOptions pipelineOptions , ITestOutputHelper ? output = default , Action < JsonNode > ? onRequest = default , Action < JsonNode > ? onResponse = default )
26- where TOptions : ClientPipelineOptions
27- {
28- pipelineOptions . AddPolicy ( new TestOutputPolicy ( output ?? NullTestOutputHelper . Default , onRequest , onResponse ) , PipelinePosition . BeforeTransport ) ;
29- return pipelineOptions ;
30- }
31-
32- class NullTestOutputHelper : ITestOutputHelper
8+ static readonly JsonSerializerOptions options = new ( JsonSerializerDefaults . General )
339 {
34- public static ITestOutputHelper Default { get ; } = new NullTestOutputHelper ( ) ;
35- NullTestOutputHelper ( ) { }
36- public void WriteLine ( string message ) { }
37- public void WriteLine ( string format , params object [ ] args ) { }
38- }
10+ WriteIndented = true ,
11+ } ;
3912
40- class TestOutputPolicy ( ITestOutputHelper output , Action < JsonNode > ? onRequest = default , Action < JsonNode > ? onResponse = default ) : PipelinePolicy
13+ public static TOptions WriteTo < TOptions > ( this TOptions pipelineOptions , ITestOutputHelper output = default )
14+ where TOptions : ClientPipelineOptions
4115 {
42- static readonly JsonSerializerOptions options = new JsonSerializerOptions ( JsonSerializerDefaults . General )
43- {
44- WriteIndented = true ,
45- } ;
46-
47- public override void Process ( PipelineMessage message , IReadOnlyList < PipelinePolicy > pipeline , int currentIndex )
48- {
49- message . BufferResponse = true ;
50- ProcessNext ( message , pipeline , currentIndex ) ;
51-
52- if ( message . Request . Content is not null )
53- {
54- using var memory = new MemoryStream ( ) ;
55- message . Request . Content . WriteTo ( memory ) ;
56- memory . Position = 0 ;
57- using var reader = new StreamReader ( memory ) ;
58- var content = reader . ReadToEnd ( ) ;
59- var node = JsonNode . Parse ( content ) ;
60- onRequest ? . Invoke ( node ! ) ;
61- output ? . WriteLine ( node ! . ToJsonString ( options ) ) ;
62- }
63-
64- if ( message . Response != null )
65- {
66- var node = JsonNode . Parse ( message . Response . Content . ToString ( ) ) ;
67- onResponse ? . Invoke ( node ! ) ;
68- output ? . WriteLine ( node ! . ToJsonString ( options ) ) ;
69- }
70- }
71-
72- public override async ValueTask ProcessAsync ( PipelineMessage message , IReadOnlyList < PipelinePolicy > pipeline , int currentIndex )
73- {
74- message . BufferResponse = true ;
75- await ProcessNextAsync ( message , pipeline , currentIndex ) ;
76-
77- if ( message . Request . Content is not null )
78- {
79- using var memory = new MemoryStream ( ) ;
80- message . Request . Content . WriteTo ( memory ) ;
81- memory . Position = 0 ;
82- using var reader = new StreamReader ( memory ) ;
83- var content = await reader . ReadToEndAsync ( ) ;
84- var node = JsonNode . Parse ( content ) ;
85- onRequest ? . Invoke ( node ! ) ;
86- output ? . WriteLine ( node ! . ToJsonString ( options ) ) ;
87- }
88-
89- if ( message . Response != null )
90- {
91- var node = JsonNode . Parse ( message . Response . Content . ToString ( ) ) ;
92- onResponse ? . Invoke ( node ! ) ;
93- output ? . WriteLine ( node ! . ToJsonString ( options ) ) ;
94- }
95- }
16+ return pipelineOptions . Observe (
17+ request => output . WriteLine ( request . ToJsonString ( options ) ) ,
18+ response => output . WriteLine ( response . ToJsonString ( options ) )
19+ ) ;
9620 }
9721}
0 commit comments