@@ -56,7 +56,7 @@ private async Task<RoleDialogModel> InnerGetChatCompletions(Agent agent, List<Ro
5656 }
5757 else if ( reason == ChatFinishReason . Length )
5858 {
59- _logger . LogWarning ( $ "Action: { nameof ( InnerGetChatCompletions ) } , Reason: { reason } , Agent: { agent . Name } , MaxOutputTokens: { options . MaxOutputTokenCount } , Content:{ text } ") ;
59+ _logger . LogWarning ( $ "Action: { nameof ( InnerGetChatCompletions ) } , Reason: { reason } , Agent: { agent . Name } , MaxOutputTokens: { options . MaxOutputTokenCount } , Content:{ DescribeContent ( text ) } , ToolCalls: { DescribeToolCalls ( ToLlmToolCalls ( value . ToolCalls ) ) } ") ;
6060
6161 responseMessage = new RoleDialogModel ( AgentRole . Assistant , $ "AI response exceeded max output length")
6262 {
@@ -176,7 +176,7 @@ private async Task<bool> InnerGetChatCompletionsAsync(Agent agent,
176176 }
177177 else if ( reason == ChatFinishReason . Length )
178178 {
179- _logger . LogWarning ( $ "Action: { nameof ( InnerGetChatCompletionsAsync ) } , Reason: { reason } , Agent: { agent . Name } , MaxOutputTokens: { options . MaxOutputTokenCount } , Content:{ text } ") ;
179+ _logger . LogWarning ( $ "Action: { nameof ( InnerGetChatCompletionsAsync ) } , Reason: { reason } , Agent: { agent . Name } , MaxOutputTokens: { options . MaxOutputTokenCount } , Content:{ DescribeContent ( text ) } , ToolCalls: { DescribeToolCalls ( ToLlmToolCalls ( value . ToolCalls ) ) } ") ;
180180
181181 msg = new RoleDialogModel ( AgentRole . Assistant , $ "AI response exceeded max output length")
182182 {
@@ -321,6 +321,13 @@ private async Task<RoleDialogModel> InnerGetChatCompletionsStreamingAsync(Agent
321321 }
322322 else if ( choice . FinishReason . HasValue )
323323 {
324+ if ( choice . FinishReason == ChatFinishReason . Length )
325+ {
326+ // What the model wrote before the limit is replaced by the notice below, so this is the only record of it
327+ _logger . LogWarning ( $ "Action: { nameof ( InnerGetChatCompletionsStreamingAsync ) } , Reason: { choice . FinishReason } , Agent: { agent . Name } , " +
328+ $ "MaxOutputTokens: { options . MaxOutputTokenCount } , Content:{ DescribeContent ( textStream . GetText ( ) ) } , ToolCalls: { DescribeToolCalls ( ReconstructToolCalls ( toolCalls ) ) } ") ;
329+ }
330+
324331 var text = choice . FinishReason == ChatFinishReason . Length ? "Model reached the maximum number of tokens allowed."
325332 : choice . FinishReason == ChatFinishReason . ContentFilter ? "Content is omitted due to content filter rule."
326333 : choice . FinishReason . Value . ToString ( ) ;
@@ -759,6 +766,20 @@ private static List<LlmToolCall> ToLlmToolCalls(IEnumerable<ChatToolCall>? toolC
759766 . Select ( x => new LlmToolCall ( x . Id , x . FunctionName , x . FunctionArguments ? . ToString ( ) ) )
760767 . ToList ( ) ;
761768
769+ /// <summary>
770+ /// The tool calls of a reply cut off by the output limit: each name and how long its arguments got. The arguments
771+ /// themselves are left out, since they can hold the user's personal data.
772+ /// </summary>
773+ internal static string DescribeToolCalls ( List < LlmToolCall > calls )
774+ => string . Join ( ", " , calls . Select ( x => $ "{ x . FunctionName } ({ x . FunctionArgs ? . Length ?? 0 } chars)") ) ;
775+
776+ /// <summary>
777+ /// What a reply cut off by the output limit said: its length and only its start, enough to tell what the model was
778+ /// writing without logging the whole reply.
779+ /// </summary>
780+ internal static string DescribeContent ( string ? text )
781+ => string . IsNullOrEmpty ( text ) ? "(none)" : $ "{ text . Length } chars: { ( text . Length > 200 ? text [ ..200 ] + "..." : text ) } ";
782+
762783 /// <summary>
763784 /// Rebuilds the tool calls a streaming reply asked for.
764785 /// </summary>
0 commit comments