feat(converter): 支持转换 url_context 和 google_maps 工具

扩展 OpenAI 和 Claude 转换器以支持将 url_context 和 google_maps 工具转换为 Gemini API 格式。现在工具数组可以包含多个独立的工具对象,而不是合并到单个对象中。
This commit is contained in:
hex2077 2026-03-30 12:00:11 +08:00
parent 6eee878574
commit 8e8a8fc551
3 changed files with 64 additions and 10 deletions

View file

@ -1 +1 @@
2.12.1
2.12.2

View file

@ -1046,13 +1046,37 @@ export class ClaudeConverter extends BaseConverter {
// 处理工具 - 使用 parametersJsonSchema 格式
if (Array.isArray(claudeRequest.tools) && claudeRequest.tools.length > 0) {
const functionDeclarations = [];
let googleSearchTool = null;
let urlContextTool = null;
let googleMapsTool = null;
claudeRequest.tools.forEach(tool => {
if (!tool || typeof tool !== 'object' || !tool.name) {
if (!tool || typeof tool !== 'object') {
logger.warn("Skipping invalid tool declaration in claudeRequest.tools.");
return;
}
// 处理 google_search 扩展
if (tool.google_search) {
googleSearchTool = tool.google_search;
}
// 处理 url_context 扩展
if (tool.url_context) {
urlContextTool = tool.url_context;
}
// 处理 google_maps 扩展
if (tool.googleMaps) {
googleMapsTool = tool.googleMaps;
}
// 如果没有名称且不是上述扩展,则跳过函数处理
if (!tool.name) {
logger.warn("Skipping unnamed tool declaration in claudeRequest.tools.");
return;
}
// 清理 input_schema
let inputSchema = tool.input_schema;
if (inputSchema && typeof inputSchema === 'object') {
@ -1077,10 +1101,20 @@ export class ClaudeConverter extends BaseConverter {
functionDeclarations.push(funcDecl);
});
if (functionDeclarations.length > 0) {
geminiRequest.tools = [{
functionDeclarations: functionDeclarations
}];
if (functionDeclarations.length > 0 || googleSearchTool || urlContextTool || googleMapsTool) {
geminiRequest.tools = [];
if (functionDeclarations.length > 0) {
geminiRequest.tools.push({ functionDeclarations });
}
if (googleSearchTool) {
geminiRequest.tools.push({ googleSearch: googleSearchTool });
}
if (urlContextTool) {
geminiRequest.tools.push({ urlContext: urlContextTool });
}
if (googleMapsTool) {
geminiRequest.tools.push({ googleMaps: googleMapsTool });
}
}
}

View file

@ -1101,6 +1101,8 @@ export class OpenAIConverter extends BaseConverter {
if (openaiRequest.tools?.length) {
const functionDeclarations = [];
let hasGoogleSearch = false;
let hasUrlContext = false;
let hasGoogleMaps = false;
for (const t of openaiRequest.tools) {
if (!t || typeof t !== 'object') continue;
@ -1135,16 +1137,34 @@ export class OpenAIConverter extends BaseConverter {
if (t.google_search) {
hasGoogleSearch = true;
}
// 处理 url_context 工具
if (t.url_context) {
hasUrlContext = true;
}
// 处理 google_maps 工具
if (t.google_maps) {
hasGoogleMaps = true;
}
}
if (functionDeclarations.length > 0 || hasGoogleSearch) {
geminiRequest.tools = [{}];
if (functionDeclarations.length > 0 || hasGoogleSearch || hasUrlContext || hasGoogleMaps) {
geminiRequest.tools = [];
if (functionDeclarations.length > 0) {
geminiRequest.tools[0].functionDeclarations = functionDeclarations;
geminiRequest.tools.push({ functionDeclarations });
}
if (hasGoogleSearch) {
const googleSearchTool = openaiRequest.tools.find(t => t.google_search);
geminiRequest.tools[0].googleSearch = googleSearchTool.google_search;
geminiRequest.tools.push({ googleSearch: googleSearchTool.google_search });
}
if (hasUrlContext) {
const urlContextTool = openaiRequest.tools.find(t => t.url_context);
geminiRequest.tools.push({ urlContext: urlContextTool.url_context });
}
if (hasGoogleMaps) {
const googleMapsTool = openaiRequest.tools.find(t => t.google_maps);
geminiRequest.tools.push({ googleMaps: googleMapsTool.google_maps });
}
}
}