1- using System . Collections . Generic ;
21using Chats . BE . Controllers . Chats . Chats ;
32using Chats . BE . DB ;
43using Chats . BE . DB . Enums ;
54using Chats . BE . Services . Models . ChatServices . OpenAI ;
65using Chats . BE . Services . Models . Dtos ;
76using Chats . BE . Services . Models . Neutral ;
87using System . Diagnostics ;
9- using System . Linq ;
10- using System . Net . Http ;
118using System . Net . Http . Headers ;
129using System . Runtime . CompilerServices ;
1310using System . Text ;
@@ -29,7 +26,7 @@ private static readonly (string Category, string Threshold)[] DefaultSafetySetti
2926 ( "HARM_CATEGORY_HARASSMENT" , "BLOCK_NONE" ) ,
3027 ] ;
3128
32- private const string DefaultEndpoint = "https://generativelanguage.googleapis.com" ;
29+ internal const string DefaultEndpoint = "https://generativelanguage.googleapis.com" ;
3330
3431 public bool AllowImageGeneration ( Model model ) => model . DeploymentName . Contains ( "gemini-2.0-flash-exp" ) ||
3532 model . DeploymentName . Contains ( "gemini-2.0-flash-exp-image-generation" ) ||
@@ -79,7 +76,7 @@ public override async IAsyncEnumerable<ChatSegment> ChatStreamed(ChatRequest req
7976 throw new RawChatServiceException ( 200 , errorMessage ) ;
8077 }
8178
82- List < ChatSegment > items = new ( ) ;
79+ List < ChatSegment > items = [ ] ;
8380 DBFinishReason ? finishReason = null ;
8481
8582 if ( chunk . TryGetProperty ( "candidates" , out JsonElement candidatesElement ) &&
@@ -299,7 +296,7 @@ private JsonObject BuildRequestBody(ChatRequest request, bool allowImageGenerati
299296
300297 private static JsonArray BuildSafetySettings ( )
301298 {
302- JsonArray safety = new ( ) ;
299+ JsonArray safety = [ ] ;
303300 foreach ( ( string Category , string Threshold ) setting in DefaultSafetySettings )
304301 {
305302 safety . Add ( new JsonObject
@@ -313,11 +310,11 @@ private static JsonArray BuildSafetySettings()
313310
314311 private static JsonObject ? BuildGenerationConfig ( ChatRequest request , bool allowImageGeneration )
315312 {
316- JsonObject config = new ( ) ;
317- JsonArray modalities = new ( )
318- {
313+ JsonObject config = [ ] ;
314+ JsonArray modalities =
315+ [
319316 "TEXT"
320- } ;
317+ ] ;
321318 if ( allowImageGeneration )
322319 {
323320 modalities . Add ( "IMAGE" ) ;
@@ -388,7 +385,7 @@ var effort when effort.IsLowOrMinimal() => 1024,
388385
389386 private static JsonArray ? BuildTools ( ChatRequest request )
390387 {
391- JsonArray tools = new ( ) ;
388+ JsonArray tools = [ ] ;
392389
393390 JsonObject ? functionTool = BuildFunctionDeclarations ( request ) ;
394391 if ( functionTool != null )
@@ -428,7 +425,7 @@ var effort when effort.IsLowOrMinimal() => 1024,
428425 return null ;
429426 }
430427
431- JsonArray declarations = new ( ) ;
428+ JsonArray declarations = [ ] ;
432429 foreach ( FunctionTool tool in functionTools )
433430 {
434431 JsonObject declaration = new ( )
@@ -480,7 +477,7 @@ private static JsonObject BuildGoogleSchema(string? openAiSchema)
480477
481478 if ( root . TryGetPropertyValue ( "properties" , out JsonNode ? propsNode ) && propsNode is JsonObject props )
482479 {
483- JsonObject properties = new ( ) ;
480+ JsonObject properties = [ ] ;
484481 foreach ( ( string key , JsonNode ? value ) in props )
485482 {
486483 if ( value is not JsonObject propertyObject )
@@ -509,7 +506,7 @@ private static JsonObject BuildGoogleSchema(string? openAiSchema)
509506
510507 if ( root . TryGetPropertyValue ( "required" , out JsonNode ? requiredNode ) && requiredNode is JsonArray requiredArray )
511508 {
512- JsonArray required = new ( ) ;
509+ JsonArray required = [ ] ;
513510 foreach ( JsonNode ? node in requiredArray )
514511 {
515512 if ( node is JsonValue value && value . TryGetValue ( out string ? str ) && str != null )
@@ -543,7 +540,7 @@ private static string ConvertSchemaType(string? type)
543540
544541 private static JsonArray ConvertMessages ( IList < NeutralMessage > messages )
545542 {
546- JsonArray result = new ( ) ;
543+ JsonArray result = [ ] ;
547544 foreach ( NeutralMessage message in messages )
548545 {
549546 JsonObject content = new ( )
@@ -561,7 +558,7 @@ private static JsonArray ConvertMessages(IList<NeutralMessage> messages)
561558 {
562559 NeutralChatRole . User => BuildUserParts ( message ) ,
563560 NeutralChatRole . Assistant => BuildAssistantParts ( message ) ,
564- NeutralChatRole . Tool => new JsonArray { ToolCallMessageToPart ( message ) } ,
561+ NeutralChatRole . Tool => [ ToolCallMessageToPart ( message ) ] ,
565562 _ => throw new NotSupportedException ( $ "Unsupported message role: { message . Role } in { nameof ( GoogleAI2ChatService ) } ") ,
566563 } ;
567564
@@ -573,7 +570,7 @@ private static JsonArray ConvertMessages(IList<NeutralMessage> messages)
573570
574571 private static JsonArray BuildUserParts ( NeutralMessage message )
575572 {
576- JsonArray parts = new ( ) ;
573+ JsonArray parts = [ ] ;
577574 foreach ( NeutralContent content in message . Contents )
578575 {
579576 JsonObject ? part = NeutralContentToGooglePart ( content ) ;
@@ -587,40 +584,68 @@ private static JsonArray BuildUserParts(NeutralMessage message)
587584
588585 private static JsonArray BuildAssistantParts ( NeutralMessage message )
589586 {
590- JsonArray parts = new ( ) ;
591-
592- foreach ( NeutralToolCallContent toolCall in message . Contents . OfType < NeutralToolCallContent > ( ) )
593- {
594- JsonObject args = ParseJson ( toolCall . Parameters ) as JsonObject ?? new JsonObject ( ) ;
595- JsonObject functionCall = new ( )
596- {
597- [ "functionCall" ] = new JsonObject
598- {
599- [ "id" ] = toolCall . Id ,
600- [ "name" ] = toolCall . Name ,
601- [ "args" ] = args
602- }
603- } ;
604- parts . Add ( functionCall ) ;
605- }
587+ JsonArray parts = [ ] ;
588+ string ? pendingThoughtSignature = null ;
606589
607590 foreach ( NeutralContent content in message . Contents )
608591 {
609- if ( content is NeutralToolCallContent )
610- {
611- continue ;
612- }
592+ switch ( content )
593+ {
594+ case NeutralThinkContent think :
595+ // https://ai.google.dev/gemini-api/docs/thought-signatures?hl=zh-cn
596+ // Don't need to care about the thinking content
597+ //if (!string.IsNullOrEmpty(think.Content))
598+ //{
599+ // parts.Add(new JsonObject
600+ // {
601+ // ["text"] = think.Content,
602+ // ["thought"] = true
603+ // });
604+ //}
605+ if ( ! string . IsNullOrEmpty ( think . Signature ) )
606+ {
607+ pendingThoughtSignature = think . Signature ;
608+ }
609+ break ;
613610
614- JsonObject ? part = NeutralContentToGooglePart ( content ) ;
615- if ( part != null )
616- {
617- parts . Add ( part ) ;
611+ case NeutralToolCallContent toolCall :
612+ JsonObject args = ParseJson ( toolCall . Parameters ) as JsonObject ?? [ ] ;
613+ JsonObject functionCall = new ( )
614+ {
615+ [ "functionCall" ] = new JsonObject
616+ {
617+ [ "id" ] = toolCall . Id ,
618+ [ "name" ] = toolCall . Name ,
619+ [ "args" ] = args
620+ }
621+ } ;
622+ AttachPendingThoughtSignature ( functionCall , ref pendingThoughtSignature ) ;
623+ parts . Add ( functionCall ) ;
624+ break ;
625+
626+ default :
627+ JsonObject ? part = NeutralContentToGooglePart ( content ) ;
628+ if ( part != null )
629+ {
630+ AttachPendingThoughtSignature ( part , ref pendingThoughtSignature ) ;
631+ parts . Add ( part ) ;
632+ }
633+ break ;
618634 }
619635 }
620636
621637 return parts ;
622638 }
623639
640+ private static void AttachPendingThoughtSignature ( JsonObject part , ref string ? pendingThoughtSignature )
641+ {
642+ if ( pendingThoughtSignature != null )
643+ {
644+ part [ "thoughtSignature" ] = pendingThoughtSignature ;
645+ pendingThoughtSignature = null ;
646+ }
647+ }
648+
624649 private static JsonObject ToolCallMessageToPart ( NeutralMessage message )
625650 {
626651 NeutralToolCallResponseContent ? responseContent = message . Contents . OfType < NeutralToolCallResponseContent > ( ) . FirstOrDefault ( ) ;
0 commit comments