@@ -73,8 +73,42 @@ export class GeminiApiClient {
7373 * 将 OpenAI 格式的消息转换为 Gemini 格式的 Content 对象。
7474 */
7575 private openAIMessageToGemini ( msg : OpenAIMessage ) : Content {
76- const role = msg . role === 'assistant' ? 'model' : 'user' ;
76+ // Handle assistant messages, which can contain both text and tool calls
77+ if ( msg . role === 'assistant' ) {
78+ const parts : Part [ ] = [ ] ;
7779
80+ // Handle text content. It can be null when tool_calls are present.
81+ if ( msg . content && typeof msg . content === 'string' ) {
82+ parts . push ( { text : msg . content } ) ;
83+ }
84+
85+ // Handle tool calls
86+ if ( msg . tool_calls && Array . isArray ( msg . tool_calls ) ) {
87+ for ( const toolCall of msg . tool_calls ) {
88+ if ( toolCall . type === 'function' && toolCall . function ) {
89+ try {
90+ // Gemini API's functionCall.args expects an object, not a string.
91+ // OpenAI's arguments is a JSON string, so it needs to be parsed.
92+ const argsObject = JSON . parse ( toolCall . function . arguments ) ;
93+ parts . push ( {
94+ functionCall : {
95+ name : toolCall . function . name ,
96+ args : argsObject ,
97+ } ,
98+ } ) ;
99+ } catch ( e ) {
100+ console . error (
101+ '[GeminiApiClient] Error parsing tool call arguments:' ,
102+ e ,
103+ ) ;
104+ }
105+ }
106+ }
107+ }
108+ return { role : 'model' , parts } ;
109+ }
110+
111+ // Handle tool responses
78112 if ( msg . role === 'tool' ) {
79113 const functionName = this . parseFunctionNameFromId ( msg . tool_call_id || '' ) ;
80114 let responsePayload : Record < string , unknown > ;
@@ -114,6 +148,9 @@ export class GeminiApiClient {
114148 } ;
115149 }
116150
151+ // Handle user and system messages
152+ const role = 'user' ; // system and user roles are mapped to 'user'
153+
117154 if ( typeof msg . content === 'string' ) {
118155 return { role, parts : [ { text : msg . content } ] } ;
119156 }
0 commit comments