route-claudecode
Version:
Advanced routing and transformation system for Claude Code outputs to multiple AI providers
172 lines • 5.68 kB
JavaScript
;
/**
* CodeWhisperer Bracket Tool Call Parser
* 基于 demo3 AIClient-2-API 的 bracket 工具调用解析逻辑
* 处理 [Called function_name with args: {...}] 格式的工具调用
* 项目所有者: Jason Zhang
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseBracketToolCalls = parseBracketToolCalls;
exports.deduplicateToolCalls = deduplicateToolCalls;
exports.cleanToolCallSyntax = cleanToolCallSyntax;
const uuid_1 = require("uuid");
const logger_1 = require("@/utils/logger");
/**
* 查找匹配的括号位置
*/
function findMatchingBracket(text, startPos) {
if (!text || startPos >= text.length || text[startPos] !== '[') {
return -1;
}
let bracketCount = 1;
let inString = false;
let escapeNext = false;
for (let i = startPos + 1; i < text.length; i++) {
const char = text[i];
if (escapeNext) {
escapeNext = false;
continue;
}
if (char === '\\' && inString) {
escapeNext = true;
continue;
}
if (char === '"' && !escapeNext) {
inString = !inString;
continue;
}
if (!inString) {
if (char === '[') {
bracketCount++;
}
else if (char === ']') {
bracketCount--;
if (bracketCount === 0) {
return i;
}
}
}
}
return -1;
}
/**
* 解析单个工具调用参数
*/
function parseToolCallArgument(jsonCandidate, functionName) {
try {
const parsedJson = JSON.parse(jsonCandidate);
let argumentsObj = parsedJson;
if (typeof argumentsObj !== 'object' || argumentsObj === null) {
return null;
}
const toolCallId = `call_${(0, uuid_1.v4)().replace(/-/g, '').substring(0, 8)}`;
return {
id: toolCallId,
type: "function",
function: {
name: functionName,
arguments: JSON.stringify(argumentsObj)
}
};
}
catch (e) {
logger_1.logger.error(`Failed to parse tool call arguments: ${e.message}`, {
jsonCandidate,
functionName
});
return null;
}
}
/**
* 解析 bracket 格式的工具调用
* 处理 [Called function_name with args: {...}] 格式
*/
function parseBracketToolCalls(responseText) {
if (!responseText || !responseText.includes("[Called")) {
return [];
}
const toolCalls = [];
let searchIndex = 0;
logger_1.logger.debug('开始解析 bracket 工具调用', {
responseLength: responseText.length,
containsPattern: responseText.includes("[Called")
});
while (true) {
const startIndex = responseText.indexOf("[Called", searchIndex);
if (startIndex === -1)
break;
const endIndex = findMatchingBracket(responseText, startIndex);
if (endIndex === -1) {
logger_1.logger.warn('无法找到匹配的括号', { startIndex });
break;
}
const bracketContent = responseText.substring(startIndex + 1, endIndex);
// 使用正则表达式匹配工具调用格式
const match = bracketContent.match(/^Called\s+(\w+)\s+with\s+args:\s*(.+)$/);
if (match) {
const functionName = match[1];
const argsString = match[2].trim();
logger_1.logger.debug('发现 bracket 工具调用', {
functionName,
argsLength: argsString.length,
argsPreview: argsString.substring(0, 100)
});
const toolCall = parseToolCallArgument(argsString, functionName);
if (toolCall) {
toolCalls.push(toolCall);
logger_1.logger.debug('成功解析 bracket 工具调用', {
toolId: toolCall.id,
functionName: toolCall.function.name
});
}
}
else {
logger_1.logger.warn('Bracket 内容格式不匹配', {
bracketContent: bracketContent.substring(0, 100)
});
}
searchIndex = endIndex + 1;
}
logger_1.logger.debug('Bracket 工具调用解析完成', {
totalFound: toolCalls.length,
toolNames: toolCalls.map(tc => tc.function.name)
});
return toolCalls;
}
/**
* 去重工具调用
*/
function deduplicateToolCalls(toolCalls) {
const seen = new Set();
const uniqueToolCalls = [];
for (const tc of toolCalls) {
const key = `${tc.function.name}-${tc.function.arguments}`;
if (!seen.has(key)) {
seen.add(key);
uniqueToolCalls.push(tc);
}
else {
logger_1.logger.debug('跳过重复的工具调用', {
functionName: tc.function.name
});
}
}
return uniqueToolCalls;
}
/**
* 清理响应文本中的工具调用语法
*/
function cleanToolCallSyntax(responseText, toolCalls) {
let cleanedText = responseText;
if (toolCalls.length > 0) {
for (const tc of toolCalls) {
const funcName = tc.function.name;
const escapedName = funcName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const pattern = new RegExp(`\\[Called\\s+${escapedName}\\s+with\\s+args:\\s*\\{[^}]*(?:\\{[^}]*\\}[^}]*)*\\}\\]`, 'gs');
cleanedText = cleanedText.replace(pattern, '');
}
cleanedText = cleanedText.replace(/\s+/g, ' ').trim();
}
return cleanedText;
}
//# sourceMappingURL=bracket-tool-parser.js.map