@@ -126,7 +126,7 @@ internal static class ModelDiagnostics
126126 {
127127 foreach ( var message in chatHistory )
128128 {
129- var formattedContent = ToGenAIConventionsFormat ( message ) ;
129+ var formattedContent = JsonSerializer . Serialize ( ToGenAIConventionsFormat ( message ) ) ;
130130 activity ? . AttachSensitiveDataAsEvent (
131131 ModelDiagnosticsTags . RoleToEventMap [ message . Role ] ,
132132 [
@@ -172,8 +172,9 @@ internal static class ModelDiagnostics
172172
173173 if ( kernel is not null && kernel . Plugins . Count > 0 )
174174 {
175- var toolDefinitions = kernel . Plugins . GetFunctionsMetadata ( ) . Select ( m => ToGenAIconventionsFormat ( m ) ) ;
176- activity ? . SetTag ( ModelDiagnosticsTags . AgentToolDefinitions , JsonSerializer . Serialize ( toolDefinitions ) ) ;
175+ activity ? . SetTag (
176+ ModelDiagnosticsTags . AgentToolDefinitions ,
177+ JsonSerializer . Serialize ( kernel . Plugins . GetFunctionsMetadata ( ) . Select ( m => ToGenAIConventionsFormat ( m ) ) ) ) ;
177178 }
178179
179180 if ( IsSensitiveEventsEnabled ( ) )
@@ -342,83 +343,45 @@ void TryAddTag(string key, string tag)
342343 }
343344
344345 /// <summary>
345- /// Convert a chat message to a string aligned with the OTel GenAI Semantic Conventions format
346+ /// Convert a chat message to a JSON object based on the OTel GenAI Semantic Conventions format
346347 /// </summary>
347- private static string ToGenAIConventionsFormat ( ChatMessageContent chatMessage , StringBuilder ? sb = null )
348+ private static object ToGenAIConventionsFormat ( ChatMessageContent chatMessage )
348349 {
349- sb ??= new StringBuilder ( ) ;
350-
351- sb . Append ( "{\" role\" : \" " ) ;
352- sb . Append ( chatMessage . Role ) ;
353- sb . Append ( "\" , \" content\" : " ) ;
354- sb . Append ( JsonSerializer . Serialize ( chatMessage . Content ) ) ;
355- if ( chatMessage . Items . OfType < FunctionCallContent > ( ) . Any ( ) )
356- {
357- sb . Append ( ", \" tool_calls\" : " ) ;
358- ToGenAIConventionsFormat ( chatMessage . Items , sb ) ;
359- }
360- if ( ! string . IsNullOrEmpty ( chatMessage . AuthorName ) )
350+ return new
361351 {
362- sb . Append ( ", \" name\" : " ) ;
363- sb . Append ( chatMessage . AuthorName ) ;
364- }
365- sb . Append ( '}' ) ;
366-
367- return sb . ToString ( ) ;
352+ role = chatMessage . Role . ToString ( ) ,
353+ name = chatMessage . AuthorName ,
354+ content = chatMessage . Content ,
355+ tool_calls = ToGenAIConventionsFormat ( chatMessage . Items ) ,
356+ } ;
368357 }
369358
370359 /// <summary>
371- /// Helper method to convert tool calls to a string aligned with the OTel GenAI Semantic Conventions format
360+ /// Helper method to convert tool calls to a list of JSON object based on the OTel GenAI Semantic Conventions format
372361 /// </summary>
373- private static void ToGenAIConventionsFormat ( ChatMessageContentItemCollection chatMessageContentItems , StringBuilder ? sb = null )
362+ private static List < object > ToGenAIConventionsFormat ( ChatMessageContentItemCollection chatMessageContentItems )
374363 {
375- sb ??= new StringBuilder ( ) ;
376-
377- sb . Append ( '[' ) ;
378- var isFirst = true ;
379- foreach ( var functionCall in chatMessageContentItems . OfType < FunctionCallContent > ( ) )
364+ return chatMessageContentItems . OfType < FunctionCallContent > ( ) . Select ( functionCall => ( object ) new
380365 {
381- if ( ! isFirst )
366+ id = functionCall . Id ,
367+ function = new
382368 {
383- // Append a comma and a newline to separate the elements after the previous one.
384- // This can avoid adding an unnecessary comma after the last element.
385- sb . Append ( ", \n " ) ;
386- }
387-
388- sb . Append ( "{\" id\" : \" " ) ;
389- sb . Append ( functionCall . Id ) ;
390- sb . Append ( "\" , \" function\" : {\" arguments\" : " ) ;
391- sb . Append ( JsonSerializer . Serialize ( functionCall . Arguments ) ) ;
392- sb . Append ( ", \" name\" : \" " ) ;
393- sb . Append ( functionCall . FunctionName ) ;
394- sb . Append ( "\" }, \" type\" : \" function\" }" ) ;
395-
396- isFirst = false ;
397- }
398- sb . Append ( ']' ) ;
399- }
400-
401- private static string ToGenAIconventionsFormat ( KernelFunctionMetadata metadata )
402- {
403- var sb = new StringBuilder ( ) ;
404-
405- sb . Append ( "{\" type\" : \" function\" , \" name\" : \" " ) ;
406- sb . Append ( metadata . Name ) ;
407- sb . Append ( "\" , \" description\" : \" " ) ;
408- sb . Append ( metadata . Description ) ;
409- sb . Append ( "\" , \" parameters\" : " ) ;
410- ToGenAIconventionsFormat ( metadata . Parameters , sb ) ;
411- sb . Append ( '}' ) ;
412-
413- return sb . ToString ( ) ;
369+ name = functionCall . FunctionName ,
370+ arguments = functionCall . Arguments
371+ } ,
372+ type = "function"
373+ } ) . ToList ( ) ;
414374 }
415375
416- private static void ToGenAIconventionsFormat ( IEnumerable < KernelParameterMetadata > parameters , StringBuilder ? sb = null )
376+ /// <summary>
377+ /// Convert a function metadata to a JSON object based on the OTel GenAI Semantic Conventions format
378+ /// </summary>
379+ private static object ToGenAIConventionsFormat ( KernelFunctionMetadata metadata )
417380 {
418381 var properties = new Dictionary < string , KernelJsonSchema > ( ) ;
419382 var required = new List < string > ( ) ;
420383
421- foreach ( var param in parameters )
384+ foreach ( var param in metadata . Parameters )
422385 {
423386 if ( param . Schema is not null )
424387 {
@@ -430,59 +393,49 @@ private static void ToGenAIconventionsFormat(IEnumerable<KernelParameterMetadata
430393 }
431394 }
432395
433- var parametersJson = JsonSerializer . Serialize ( new
396+ return new
434397 {
435- type = "object" ,
436- properties ,
437- required ,
438- } ) ;
439-
440- sb ??= new StringBuilder ( ) ;
441- sb . Append ( parametersJson ) ;
398+ type = "function" ,
399+ name = metadata . Name ,
400+ description = metadata . Description ,
401+ parameters = new
402+ {
403+ type = "object" ,
404+ properties ,
405+ required ,
406+ }
407+ } ;
442408 }
443409
444410 /// <summary>
445- /// Convert a chat model response to a string aligned with the OTel GenAI Semantic Conventions format
411+ /// Convert a chat model response to a JSON string based on the OTel GenAI Semantic Conventions format
446412 /// </summary>
447413 private static string ToGenAIConventionsChoiceFormat ( ChatMessageContent chatMessage , int index )
448414 {
449- var sb = new StringBuilder ( ) ;
450-
451- sb . Append ( "{\" index\" : " ) ;
452- sb . Append ( index ) ;
453- sb . Append ( ", \" message\" : " ) ;
454- ToGenAIConventionsFormat ( chatMessage , sb ) ;
455- sb . Append ( ", \" tool_calls\" : " ) ;
456- ToGenAIConventionsFormat ( chatMessage . Items , sb ) ;
457- if ( chatMessage . Metadata ? . TryGetValue ( "FinishReason" , out var finishReason ) == true )
458- {
459- sb . Append ( ", \" finish_reason\" : " ) ;
460- sb . Append ( JsonSerializer . Serialize ( finishReason ) ) ;
461- }
462- sb . Append ( '}' ) ;
415+ var jsonObject = new
416+ {
417+ index ,
418+ message = ToGenAIConventionsFormat ( chatMessage ) ,
419+ tool_calls = ToGenAIConventionsFormat ( chatMessage . Items ) ,
420+ finish_reason = chatMessage . Metadata ? . TryGetValue ( "FinishReason" , out var finishReason ) == true ? finishReason : null
421+ } ;
463422
464- return sb . ToString ( ) ;
423+ return JsonSerializer . Serialize ( jsonObject ) ;
465424 }
466425
467426 /// <summary>
468- /// Convert a text model response to a string aligned with the OTel GenAI Semantic Conventions format
427+ /// Convert a text model response to a JSON string based on the OTel GenAI Semantic Conventions format
469428 /// </summary>
470429 private static string ToGenAIConventionsChoiceFormat ( TextContent textContent , int index )
471430 {
472- var sb = new StringBuilder ( ) ;
473-
474- sb . Append ( "{\" index\" : " ) ;
475- sb . Append ( index ) ;
476- sb . Append ( ", \" message\" : " ) ;
477- sb . Append ( JsonSerializer . Serialize ( textContent . Text ) ) ;
478- if ( textContent . Metadata ? . TryGetValue ( "FinishReason" , out var finishReason ) == true )
431+ var jsonObject = new
479432 {
480- sb . Append ( ", \" finish_reason \" : " ) ;
481- sb . Append ( JsonSerializer . Serialize ( finishReason ) ) ;
482- }
483- sb . Append ( '}' ) ;
433+ index ,
434+ message = textContent . Text ,
435+ finish_reason = textContent . Metadata ? . TryGetValue ( "FinishReason" , out var finishReason ) == true ? finishReason : null
436+ } ;
484437
485- return sb . ToString ( ) ;
438+ return JsonSerializer . Serialize ( jsonObject ) ;
486439 }
487440
488441 /// <summary>
0 commit comments