@@ -665,41 +665,267 @@ def convert_kiro_response_to_openai(result: dict, model: str, msg_id: str) -> di
665665
666666# ==================== Gemini 转换 ====================
667667
668- def convert_gemini_contents_to_kiro (contents : List [dict ], system_instruction : dict , model : str ) -> Tuple [str , List [dict ]]:
669- """将 Gemini 消息格式转换为 Kiro 格式"""
668+ def convert_gemini_tools_to_kiro (tools : List [dict ]) -> List [dict ]:
669+ """将 Gemini 工具格式转换为 Kiro 格式
670+
671+ Gemini 工具格式:
672+ {
673+ "functionDeclarations": [
674+ {
675+ "name": "get_weather",
676+ "description": "Get weather info",
677+ "parameters": {...}
678+ }
679+ ]
680+ }
681+ """
682+ kiro_tools = []
683+ function_count = 0
684+
685+ for tool in tools :
686+ # Gemini 的工具定义在 functionDeclarations 中
687+ declarations = tool .get ("functionDeclarations" , [])
688+
689+ for func in declarations :
690+ # 限制工具数量
691+ if function_count >= MAX_TOOLS :
692+ break
693+ function_count += 1
694+
695+ name = func .get ("name" , "" )
696+ description = func .get ("description" , f"Tool: { name } " )
697+ description = truncate_description (description )
698+ parameters = func .get ("parameters" , {"type" : "object" , "properties" : {}})
699+
700+ kiro_tools .append ({
701+ "toolSpecification" : {
702+ "name" : name ,
703+ "description" : description ,
704+ "inputSchema" : {
705+ "json" : parameters
706+ }
707+ }
708+ })
709+
710+ return kiro_tools
711+
712+
713+ def convert_gemini_contents_to_kiro (
714+ contents : List [dict ],
715+ system_instruction : dict ,
716+ model : str ,
717+ tools : List [dict ] = None ,
718+ tool_config : dict = None
719+ ) -> Tuple [str , List [dict ], List [dict ], List [dict ]]:
720+ """将 Gemini 消息格式转换为 Kiro 格式
721+
722+ 增强:
723+ - 支持 functionCall 和 functionResponse
724+ - 支持 tool_config
725+
726+ Returns:
727+ (user_content, history, tool_results, kiro_tools)
728+ """
670729 history = []
671730 user_content = ""
731+ current_tool_results = []
732+ pending_tool_results = []
672733
734+ # 处理 system instruction
673735 system_text = ""
674736 if system_instruction :
675737 parts = system_instruction .get ("parts" , [])
676738 system_text = " " .join (p .get ("text" , "" ) for p in parts if "text" in p )
677739
678- for content in contents :
740+ # 处理 tool_config(类似 tool_choice)
741+ tool_instruction = ""
742+ if tool_config :
743+ mode = tool_config .get ("functionCallingConfig" , {}).get ("mode" , "" )
744+ if mode in ("ANY" , "REQUIRED" ):
745+ tool_instruction = "\n \n [CRITICAL INSTRUCTION] You MUST use one of the provided tools to respond. Do NOT respond with plain text."
746+
747+ for i , content in enumerate (contents ):
679748 role = content .get ("role" , "user" )
680749 parts = content .get ("parts" , [])
681- text = " " .join (p .get ("text" , "" ) for p in parts if "text" in p )
750+ is_last = (i == len (contents ) - 1 )
751+
752+ # 提取文本和工具调用
753+ text_parts = []
754+ tool_calls = []
755+ tool_responses = []
756+
757+ for part in parts :
758+ if "text" in part :
759+ text_parts .append (part ["text" ])
760+ elif "functionCall" in part :
761+ # Gemini 的工具调用
762+ fc = part ["functionCall" ]
763+ tool_calls .append ({
764+ "toolUseId" : fc .get ("name" , "" ) + "_" + str (i ), # Gemini 没有 ID,生成一个
765+ "name" : fc .get ("name" , "" ),
766+ "input" : fc .get ("args" , {})
767+ })
768+ elif "functionResponse" in part :
769+ # Gemini 的工具响应
770+ fr = part ["functionResponse" ]
771+ response_content = fr .get ("response" , {})
772+ if isinstance (response_content , dict ):
773+ response_text = json .dumps (response_content )
774+ else :
775+ response_text = str (response_content )
776+
777+ tool_responses .append ({
778+ "content" : [{"text" : response_text }],
779+ "status" : "success" ,
780+ "toolUseId" : fr .get ("name" , "" ) + "_" + str (i - 1 ) # 匹配上一个调用
781+ })
782+
783+ text = " " .join (text_parts )
682784
683785 if role == "user" :
786+ # 处理待处理的 tool responses
787+ if pending_tool_results :
788+ seen_ids = set ()
789+ unique_results = []
790+ for tr in pending_tool_results :
791+ if tr ["toolUseId" ] not in seen_ids :
792+ seen_ids .add (tr ["toolUseId" ])
793+ unique_results .append (tr )
794+
795+ history .append ({
796+ "userInputMessage" : {
797+ "content" : "Tool results provided." ,
798+ "modelId" : model ,
799+ "origin" : "AI_EDITOR" ,
800+ "userInputMessageContext" : {
801+ "toolResults" : unique_results
802+ }
803+ }
804+ })
805+ pending_tool_results = []
806+
807+ # 处理 functionResponse(用户消息中的工具响应)
808+ if tool_responses :
809+ pending_tool_results .extend (tool_responses )
810+
811+ # 合并 system prompt
684812 if system_text and not history :
685- text = f"{ system_text } \n \n { text } "
686- history .append ({
687- "userInputMessage" : {
688- "content" : text ,
689- "modelId" : model ,
690- "origin" : "AI_EDITOR"
691- }
692- })
693- user_content = text
813+ text = f"{ system_text } { tool_instruction } \n \n { text } "
814+
815+ if is_last :
816+ user_content = text
817+ if pending_tool_results :
818+ current_tool_results = pending_tool_results
819+ pending_tool_results = []
820+ else :
821+ if text :
822+ history .append ({
823+ "userInputMessage" : {
824+ "content" : text ,
825+ "modelId" : model ,
826+ "origin" : "AI_EDITOR"
827+ }
828+ })
829+
694830 elif role == "model" :
831+ # 处理待处理的 tool responses
832+ if pending_tool_results :
833+ seen_ids = set ()
834+ unique_results = []
835+ for tr in pending_tool_results :
836+ if tr ["toolUseId" ] not in seen_ids :
837+ seen_ids .add (tr ["toolUseId" ])
838+ unique_results .append (tr )
839+
840+ history .append ({
841+ "userInputMessage" : {
842+ "content" : "Tool results provided." ,
843+ "modelId" : model ,
844+ "origin" : "AI_EDITOR" ,
845+ "userInputMessageContext" : {
846+ "toolResults" : unique_results
847+ }
848+ }
849+ })
850+ pending_tool_results = []
851+
852+ assistant_text = text if text else "I understand."
853+
695854 history .append ({
696855 "assistantResponseMessage" : {
697- "content" : text if text else "I understand." ,
698- "toolUses" : []
856+ "content" : assistant_text ,
857+ "toolUses" : tool_calls
699858 }
700859 })
701860
861+ # 处理末尾的 tool results
862+ if pending_tool_results :
863+ current_tool_results = pending_tool_results
864+ if not user_content :
865+ user_content = "Tool results provided."
866+
867+ # 如果没有用户消息
868+ if not user_content :
869+ if contents :
870+ last_parts = contents [- 1 ].get ("parts" , [])
871+ user_content = " " .join (p .get ("text" , "" ) for p in last_parts if "text" in p )
872+ if not user_content :
873+ user_content = "Continue"
874+
702875 # 修复历史交替
703876 history = fix_history_alternation (history , model )
704877
705- return user_content , history [:- 1 ] if history else []
878+ # 移除最后一条(当前用户消息)
879+ if history and "userInputMessage" in history [- 1 ]:
880+ history = history [:- 1 ]
881+
882+ # 转换工具
883+ kiro_tools = convert_gemini_tools_to_kiro (tools ) if tools else []
884+
885+ return user_content , history , current_tool_results , kiro_tools
886+
887+
888+ def convert_kiro_response_to_gemini (result : dict , model : str ) -> dict :
889+ """将 Kiro 响应转换为 Gemini 格式"""
890+ text = "" .join (result .get ("content" , []))
891+ tool_uses = result .get ("tool_uses" , [])
892+
893+ parts = []
894+
895+ # 添加文本部分
896+ if text :
897+ parts .append ({"text" : text })
898+
899+ # 添加工具调用
900+ for tool_use in tool_uses :
901+ if tool_use .get ("type" ) == "tool_use" :
902+ parts .append ({
903+ "functionCall" : {
904+ "name" : tool_use .get ("name" , "" ),
905+ "args" : tool_use .get ("input" , {})
906+ }
907+ })
908+
909+ # 映射 stop_reason
910+ stop_reason = result .get ("stop_reason" , "STOP" )
911+ finish_reason = "STOP"
912+ if tool_uses :
913+ finish_reason = "TOOL_CALLS"
914+ elif stop_reason == "max_tokens" :
915+ finish_reason = "MAX_TOKENS"
916+
917+ return {
918+ "candidates" : [{
919+ "content" : {
920+ "parts" : parts ,
921+ "role" : "model"
922+ },
923+ "finishReason" : finish_reason ,
924+ "index" : 0
925+ }],
926+ "usageMetadata" : {
927+ "promptTokenCount" : 100 ,
928+ "candidatesTokenCount" : 100 ,
929+ "totalTokenCount" : 200
930+ }
931+ }
0 commit comments