- 新增 translate.ts: 实现有道翻译API调用 - 支持100+种语言互译 - 自动语言检测 - SHA256签名验证 - 完善的错误码处理 - executor.ts: 添加翻译工具执行器 - 支持源语言/目标语言参数 - 格式化翻译结果输出 - route.ts: 添加翻译工具定义 - Claude/OpenAI/Codex三种格式支持
289 lines
8.8 KiB
TypeScript
289 lines
8.8 KiB
TypeScript
/**
|
||
* 统一工具执行器
|
||
* 根据工具名称和输入参数执行对应的工具
|
||
*/
|
||
|
||
import {
|
||
webSearch,
|
||
formatSearchResults,
|
||
formatSearchResultsShort,
|
||
type WebSearchInput,
|
||
type WebSearchResponse,
|
||
} from './webSearch';
|
||
import {
|
||
executeCode,
|
||
formatExecutionResult,
|
||
formatExecutionResultShort,
|
||
type CodeExecutionInput,
|
||
type CodeExecutionResponse,
|
||
} from './codeExecution';
|
||
import {
|
||
webFetch,
|
||
formatFetchResult,
|
||
formatFetchResultShort,
|
||
type WebFetchInput,
|
||
type WebFetchResponse,
|
||
} from './webFetch';
|
||
import {
|
||
metasoSearch,
|
||
formatMetasoSearchResults,
|
||
formatMetasoSearchResultsShort,
|
||
getValidImages,
|
||
ImageValidationConfig,
|
||
type MetasoSearchInput,
|
||
type MetasoSearchResponse,
|
||
type MetasoImageResult,
|
||
type MetasoVideoResult,
|
||
} from './metasoSearch';
|
||
import {
|
||
metasoReader,
|
||
formatMetasoReaderResult,
|
||
formatMetasoReaderResultShort,
|
||
type MetasoReaderInput,
|
||
type MetasoReaderResponse,
|
||
} from './metasoReader';
|
||
import {
|
||
translate,
|
||
formatTranslateResult,
|
||
formatTranslateResultShort,
|
||
type TranslateInput,
|
||
type TranslateResponse,
|
||
} from './translate';
|
||
import { shouldUsePyodide, analyzeCode, type LoadingCallback } from './codeAnalyzer';
|
||
|
||
// 导出代码分析函数供外部使用
|
||
export { shouldUsePyodide, analyzeCode, type LoadingCallback } from './codeAnalyzer';
|
||
|
||
export interface ToolExecutionResult {
|
||
success: boolean;
|
||
/** 完整结果 - 发送给 AI */
|
||
fullResult: string;
|
||
/** 简短结果 - 显示给用户 */
|
||
displayResult: string;
|
||
/** 原始数据 */
|
||
rawData?: unknown;
|
||
/** Base64 编码的图片数组(代码执行时可能产生) */
|
||
images?: string[];
|
||
/** 搜索到的图片数组(图片搜索时产生) */
|
||
searchImages?: MetasoImageResult[];
|
||
/** 搜索到的视频数组(视频搜索时产生) */
|
||
searchVideos?: MetasoVideoResult[];
|
||
/** 是否需要浏览器端 Pyodide 执行 */
|
||
requiresPyodide?: boolean;
|
||
/** 代码内容(当 requiresPyodide 为 true 时) */
|
||
code?: string;
|
||
/** 语言(当 requiresPyodide 为 true 时) */
|
||
language?: string;
|
||
}
|
||
|
||
export interface ToolExecutionOptions {
|
||
/** Pyodide 加载进度回调 */
|
||
onProgress?: LoadingCallback;
|
||
/** 秘塔AI API Key */
|
||
metasoApiKey?: string;
|
||
}
|
||
|
||
/**
|
||
* 执行工具
|
||
* @param toolName 工具名称
|
||
* @param input 工具输入参数
|
||
* @param options 执行选项
|
||
* @returns 执行结果(包含完整版和简短版)
|
||
*/
|
||
export async function executeTool(
|
||
toolName: string,
|
||
input: Record<string, unknown>,
|
||
options?: ToolExecutionOptions
|
||
): Promise<ToolExecutionResult> {
|
||
const { onProgress, metasoApiKey } = options || {};
|
||
try {
|
||
switch (toolName) {
|
||
case 'web_search': {
|
||
const query = String(input.query || '');
|
||
const searchInput: WebSearchInput = { query };
|
||
const response: WebSearchResponse = await webSearch(searchInput);
|
||
return {
|
||
success: response.success,
|
||
fullResult: formatSearchResults(response),
|
||
displayResult: formatSearchResultsShort(response, query),
|
||
rawData: response,
|
||
};
|
||
}
|
||
|
||
case 'code_execution': {
|
||
const language = String(input.language || 'python');
|
||
const code = String(input.code || '');
|
||
|
||
// 检测是否需要浏览器端 Pyodide 执行(Python + 图形代码)
|
||
if (shouldUsePyodide(code, language)) {
|
||
return {
|
||
success: true,
|
||
fullResult: '需要在浏览器端执行 Python 图形代码',
|
||
displayResult: '检测到图形绑制代码,正在准备浏览器端执行...',
|
||
requiresPyodide: true,
|
||
code,
|
||
language,
|
||
};
|
||
}
|
||
|
||
// 使用 Piston API 执行(服务端)
|
||
const codeInput: CodeExecutionInput = {
|
||
code,
|
||
language,
|
||
stdin: input.stdin ? String(input.stdin) : undefined,
|
||
onProgress, // 传递 Pyodide 加载进度回调
|
||
};
|
||
const response: CodeExecutionResponse = await executeCode(codeInput);
|
||
return {
|
||
success: response.success,
|
||
fullResult: formatExecutionResult(response),
|
||
displayResult: formatExecutionResultShort(response, language),
|
||
rawData: response,
|
||
images: response.images, // 传递图片数据
|
||
};
|
||
}
|
||
|
||
case 'web_fetch': {
|
||
const fetchInput: WebFetchInput = {
|
||
url: String(input.url || ''),
|
||
};
|
||
const response: WebFetchResponse = await webFetch(fetchInput);
|
||
return {
|
||
success: response.success,
|
||
fullResult: formatFetchResult(response),
|
||
displayResult: formatFetchResultShort(response),
|
||
rawData: response,
|
||
};
|
||
}
|
||
|
||
case 'mita_search': {
|
||
const query = String(input.query || '');
|
||
const scope = (input.scope as 'webpage' | 'image' | 'video') || 'webpage';
|
||
|
||
// 图片搜索时请求更多图片用于验证筛选,视频和网页搜索保持原有逻辑
|
||
const requestSize = scope === 'image'
|
||
? ImageValidationConfig.REQUEST_SIZE
|
||
: (input.size ? Number(input.size) : (scope === 'video' ? 5 : 10));
|
||
|
||
const searchInput: MetasoSearchInput = {
|
||
query,
|
||
scope,
|
||
size: requestSize,
|
||
includeSummary: Boolean(input.includeSummary),
|
||
};
|
||
|
||
const response: MetasoSearchResponse = await metasoSearch(searchInput, metasoApiKey || '');
|
||
|
||
// 如果是图片搜索且成功,验证图片有效性
|
||
let validatedImages: MetasoImageResult[] | undefined;
|
||
if (scope === 'image' && response.success && response.images && response.images.length > 0) {
|
||
// 验证图片,返回指定数量的有效图片
|
||
validatedImages = await getValidImages(
|
||
response.images,
|
||
ImageValidationConfig.TARGET_COUNT,
|
||
ImageValidationConfig.CONCURRENCY
|
||
);
|
||
|
||
// 更新 response 中的图片为验证后的有效图片
|
||
response.images = validatedImages;
|
||
}
|
||
|
||
return {
|
||
success: response.success,
|
||
fullResult: formatMetasoSearchResults(response),
|
||
displayResult: formatMetasoSearchResultsShort(response, query),
|
||
rawData: response,
|
||
// 如果是图片搜索,返回验证后的图片数据
|
||
searchImages: scope === 'image' ? validatedImages : undefined,
|
||
// 如果是视频搜索,返回视频数据
|
||
searchVideos: scope === 'video' ? response.videos : undefined,
|
||
};
|
||
}
|
||
|
||
case 'mita_reader': {
|
||
const url = String(input.url || '');
|
||
const readerInput: MetasoReaderInput = {
|
||
url,
|
||
format: 'Markdown',
|
||
};
|
||
const response: MetasoReaderResponse = await metasoReader(readerInput, metasoApiKey || '');
|
||
return {
|
||
success: response.success,
|
||
fullResult: formatMetasoReaderResult(response, url),
|
||
displayResult: formatMetasoReaderResultShort(response, url),
|
||
rawData: response,
|
||
};
|
||
}
|
||
|
||
case 'youdao_translate': {
|
||
const text = String(input.text || '');
|
||
const from = input.from ? String(input.from) : 'auto';
|
||
const to = input.to ? String(input.to) : 'zh-CHS';
|
||
|
||
const translateInput: TranslateInput = { text, from, to };
|
||
const response: TranslateResponse = await translate(translateInput);
|
||
|
||
return {
|
||
success: response.success,
|
||
fullResult: formatTranslateResult(response, text),
|
||
displayResult: formatTranslateResultShort(response, text),
|
||
rawData: response,
|
||
};
|
||
}
|
||
|
||
default:
|
||
return {
|
||
success: false,
|
||
fullResult: `未知的工具: ${toolName}`,
|
||
displayResult: `未知的工具: ${toolName}`,
|
||
};
|
||
}
|
||
} catch (error) {
|
||
console.error(`Tool execution error (${toolName}):`, error);
|
||
const errorMsg = error instanceof Error ? error.message : '未知错误';
|
||
return {
|
||
success: false,
|
||
fullResult: `工具执行错误: ${errorMsg}`,
|
||
displayResult: `工具执行错误: ${errorMsg}`,
|
||
};
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取所有可用工具的信息
|
||
*/
|
||
export function getAvailableTools() {
|
||
return [
|
||
{
|
||
id: 'web_search',
|
||
name: '网络搜索',
|
||
description: '搜索互联网获取最新信息',
|
||
icon: '🔍',
|
||
},
|
||
{
|
||
id: 'web_fetch',
|
||
name: '网页获取',
|
||
description: '获取指定 URL 的网页内容',
|
||
icon: '🌐',
|
||
},
|
||
{
|
||
id: 'mita_search',
|
||
name: 'Metaso Search',
|
||
description: '秘塔AI智能搜索,需要配置API Key',
|
||
icon: '🔎',
|
||
},
|
||
{
|
||
id: 'mita_reader',
|
||
name: 'Metaso Reader',
|
||
description: '秘塔AI网页读取,返回Markdown格式',
|
||
icon: '📄',
|
||
},
|
||
{
|
||
id: 'youdao_translate',
|
||
name: '翻译',
|
||
description: '有道智云高质量多语言翻译,支持100+种语言',
|
||
icon: '🌐',
|
||
},
|
||
];
|
||
}
|