Skip to content

Commit f62a0dd

Browse files
refactor: 正确处理 assistant 消息中的工具调用
Co-authored-by: aider (vertex_ai/gemini-2.5-pro) <aider@aider.chat>
1 parent 6cbbf75 commit f62a0dd

File tree

2 files changed

+63
-4
lines changed

2 files changed

+63
-4
lines changed

packages/mcp-server/src/gemini-client.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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
}

packages/mcp-server/src/types.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,42 @@ export interface MessageContentPart {
1414
};
1515
}
1616

17+
// OpenAI 工具调用对象
18+
export interface OpenAIToolCall {
19+
id: string;
20+
type: 'function';
21+
function: {
22+
name: string;
23+
arguments: string; // 这是一个 JSON 字符串
24+
};
25+
}
26+
1727
// OpenAI 请求体中的消息对象
1828
export interface OpenAIMessage {
1929
role: 'system' | 'user' | 'assistant' | 'tool';
20-
content: string | MessageContentPart[];
21-
tool_calls?: any; // 根据需要定义更精确的类型
30+
content: string | null | MessageContentPart[]; // 当 tool_calls 存在时,content 可能为 null
31+
tool_calls?: OpenAIToolCall[];
2232
tool_call_id?: string;
2333
}
2434

35+
// OpenAI 工具定义
36+
export interface OpenAIFunction {
37+
name: string;
38+
description?: string;
39+
parameters: Record<string, unknown>; // JSON Schema object
40+
}
41+
42+
export interface OpenAITool {
43+
type: 'function';
44+
function: OpenAIFunction;
45+
}
46+
2547
// OpenAI Chat Completion 请求体
2648
export interface OpenAIChatCompletionRequest {
2749
model: string;
2850
messages: OpenAIMessage[];
2951
stream?: boolean;
30-
tools?: any[]; // 对应 Gemini 的 Tool[]
52+
tools?: OpenAITool[]; // 对应 Gemini 的 Tool[]
3153
tool_choice?: any; // 对应 Gemini 的 ToolConfig
3254
}
3355

0 commit comments

Comments
 (0)