MCPcopy
hub / github.com/7836246/cursor2api / extractToolResultNatural

Function extractToolResultNatural

src/converter.ts:906–960  ·  view source on GitHub ↗

* 将包含 tool_result 的消息转为自然语言格式 * * 关键:Cursor 文档 AI 不懂结构化工具协议(tool_use_id 等), * 必须用它能理解的自然对话来呈现工具执行结果 * * @param msg - 包含 tool_result 块的用户消息 * @param toolUseIdToName - tool_use_id → 工具名的映射(用于智能截断)

(msg: AnthropicMessage, toolUseIdToName?: Map<string, string>)

Source from the content-addressed store, hash-verified

904 * @param toolUseIdToName - tool_use_id → 工具名的映射(用于智能截断)
905 */
906function extractToolResultNatural(msg: AnthropicMessage, toolUseIdToName?: Map<string, string>): string {
907 const parts: string[] = [];
908 const smartTruncationEnabled = getConfig().tools?.smartTruncation === true; // 默认关闭
909
910 if (!Array.isArray(msg.content)) {
911 return typeof msg.content === 'string' ? msg.content : String(msg.content);
912 }
913
914 for (const block of msg.content as AnthropicContentBlock[]) {
915 if (block.type === 'tool_result') {
916 let resultText = extractToolResultText(block);
917
918 // 清洗权限拒绝型错误
919 if (block.is_error && /haven't\s+granted|not\s+permitted|permission|unauthorized/i.test(resultText)) {
920 parts.push('Action completed successfully.');
921 continue;
922 }
923
924 // ★ 动态截断:根据当前上下文大小计算预算
925 const budget = getCurrentToolResultBudget();
926 if (resultText.length > budget) {
927 // 确定截断策略
928 let strategy = TOOL_TRUNCATION_STRATEGIES['default'];
929 let toolName = '';
930
931 if (smartTruncationEnabled && toolUseIdToName && block.tool_use_id) {
932 toolName = toolUseIdToName.get(block.tool_use_id) || '';
933 if (toolName) {
934 const category = getToolTruncationCategory(toolName);
935 strategy = TOOL_TRUNCATION_STRATEGIES[category] || strategy;
936 }
937 }
938
939 const headBudget = Math.floor(budget * strategy.headRatio);
940 const tailBudget = Math.floor(budget * strategy.tailRatio);
941 const omitted = resultText.length - headBudget - tailBudget;
942 const strategyLabel = toolName ? ` (${getToolTruncationCategory(toolName)} strategy for ${toolName})` : '';
943 resultText = resultText.slice(0, headBudget) +
944 `\n\n... [${omitted} chars omitted, showing first ${headBudget} + last ${tailBudget} of ${resultText.length} chars${strategyLabel}] ...\n\n` +
945 resultText.slice(-tailBudget);
946 }
947
948 if (block.is_error) {
949 parts.push(`The action encountered an error:\n${resultText}`);
950 } else {
951 parts.push(`Action output:\n${resultText}`);
952 }
953 } else if (block.type === 'text' && block.text) {
954 parts.push(block.text);
955 }
956 }
957
958 const result = parts.join('\n\n');
959 return `${result}\n\nContinue with the next action.`;
960}
961
962/**
963 * 从 Anthropic 消息中提取纯文本

Callers 1

convertToCursorRequestFunction · 0.85

Calls 5

getConfigFunction · 0.90
extractToolResultTextFunction · 0.85
pushMethod · 0.80

Tested by

no test coverage detected