Browse Source

上传 mcp 参数解析bug修复

weicu
liwei1dao 1 year ago
parent
commit
e4ee5a18dc
  1. 57
      local_plugins/open_ai_service/android/src/main/kotlin/com/yunqiinnovation/open_ai_service/MCPClient.kt

57
local_plugins/open_ai_service/android/src/main/kotlin/com/yunqiinnovation/open_ai_service/MCPClient.kt

@ -201,31 +201,21 @@ class MCPSubClient(
toolMaps.clear() toolMaps.clear()
try { try {
// 转换MCP工具为OpenAI函数格式
tools.forEach { toolUnion -> tools.forEach { toolUnion ->
val tool = toolUnion.tool().getOrNull() ?: return@forEach val tool = toolUnion.tool().getOrNull() ?: return@forEach
try { try {
// 获取工具的输入模式
val inputSchema = tool.inputSchema() ?: return@forEach val inputSchema = tool.inputSchema() ?: return@forEach
// 使用toString()获取完整JSON字符串
val schemaStr = inputSchema.toString() val schemaStr = inputSchema.toString()
Log.d(TAG, "工具 ${tool.name()} 的Schema: $schemaStr") Log.d(TAG, "工具 ${tool.name()} 的Schema: $schemaStr")
// 解析properties和required
val propertiesMap = HashMap<String, Any>() val propertiesMap = HashMap<String, Any>()
val requiredList = ArrayList<String>() val requiredList = ArrayList<String>()
try { try {
// 匹配properties内部的内容 // ✅ 替换原来的正则方式,使用括号匹配方式提取 properties 内容
val propertiesPattern = "properties=\\{(.*?)\\}(?:,|\\s|$)".toRegex(RegexOption.DOT_MATCHES_ALL) val propertiesContent = extractPropertiesContent(schemaStr)
val propertiesMatch = propertiesPattern.find(schemaStr) if (propertiesContent != null) {
if (propertiesMatch != null) {
val propertiesContent = propertiesMatch.groupValues[1]
// 匹配每个属性字段,例如 query={description=搜索信息, type=string}
val fieldPattern = "([a-zA-Z0-9_]+)=\\{([^{}]+?)\\}".toRegex() val fieldPattern = "([a-zA-Z0-9_]+)=\\{([^{}]+?)\\}".toRegex()
val fieldMatches = fieldPattern.findAll(propertiesContent) val fieldMatches = fieldPattern.findAll(propertiesContent)
@ -233,11 +223,7 @@ class MCPSubClient(
val fieldName = fieldMatch.groupValues[1] val fieldName = fieldMatch.groupValues[1]
val fieldContent = fieldMatch.groupValues[2] val fieldContent = fieldMatch.groupValues[2]
// 解析字段属性
val fieldMap = HashMap<String, Any>() val fieldMap = HashMap<String, Any>()
// 解析如 description=搜索信息, type=string 格式的键值对
// 同时处理带引号和不带引号的情况
val keyValuePattern = "([a-zA-Z0-9_]+)=(\"[^\"]*\"|'[^']*'|[^,}\\s]+)".toRegex() val keyValuePattern = "([a-zA-Z0-9_]+)=(\"[^\"]*\"|'[^']*'|[^,}\\s]+)".toRegex()
val keyValueMatches = keyValuePattern.findAll(fieldContent) val keyValueMatches = keyValuePattern.findAll(fieldContent)
@ -245,39 +231,34 @@ class MCPSubClient(
val key = kvMatch.groupValues[1] val key = kvMatch.groupValues[1]
var value = kvMatch.groupValues[2].trim() var value = kvMatch.groupValues[2].trim()
// 去除引号(如果有)
if ((value.startsWith("\"") && value.endsWith("\"")) || if ((value.startsWith("\"") && value.endsWith("\"")) ||
(value.startsWith("'") && value.endsWith("'"))) { (value.startsWith("'") && value.endsWith("'"))) {
value = value.substring(1, value.length - 1) value = value.substring(1, value.length - 1)
} }
// 处理不同类型的值
val processedValue: Any = when { val processedValue: Any = when {
value.equals("true", ignoreCase = true) -> true value.equals("true", ignoreCase = true) -> true
value.equals("false", ignoreCase = true) -> false value.equals("false", ignoreCase = true) -> false
value.matches("\\d+".toRegex()) -> value.toIntOrNull() ?: value value.matches("\\d+".toRegex()) -> value.toIntOrNull() ?: value
value.matches("\\d+\\.\\d+".toRegex()) -> value.toDoubleOrNull() ?: value value.matches("\\d+\\.\\d+".toRegex()) -> value.toDoubleOrNull() ?: value
else -> value // 保持为字符串 else -> value
} }
fieldMap[key] = processedValue fieldMap[key] = processedValue
} }
// 添加到属性映射
propertiesMap[fieldName] = fieldMap propertiesMap[fieldName] = fieldMap
} }
Log.d(TAG, "成功解析属性: $propertiesMap") Log.d(TAG, "成功解析属性: $propertiesMap")
} }
// 解析required // ✅ required 部分保持不变
val requiredPattern = "required=\\[(.*?)\\]".toRegex() val requiredPattern = "required=\\[(.*?)\\]".toRegex()
val requiredMatch = requiredPattern.find(schemaStr) val requiredMatch = requiredPattern.find(schemaStr)
if (requiredMatch != null) { if (requiredMatch != null) {
val requiredStr = requiredMatch.groupValues[1] val requiredStr = requiredMatch.groupValues[1]
if (requiredStr.isNotEmpty()) { if (requiredStr.isNotEmpty()) {
// 处理可能带引号的字段名
val fieldNames = requiredStr.split(",").map { val fieldNames = requiredStr.split(",").map {
val trimmed = it.trim() val trimmed = it.trim()
if ((trimmed.startsWith("\"") && trimmed.endsWith("\"")) || if ((trimmed.startsWith("\"") && trimmed.endsWith("\"")) ||
@ -296,7 +277,6 @@ class MCPSubClient(
Log.e(TAG, "原始Schema: $schemaStr") Log.e(TAG, "原始Schema: $schemaStr")
} }
// 创建OpenAI函数格式
val functionMap = mapOf( val functionMap = mapOf(
"name" to tool.name(), "name" to tool.name(),
"description" to (tool.description() ?: ""), "description" to (tool.description() ?: ""),
@ -307,7 +287,6 @@ class MCPSubClient(
) )
) )
// 添加到工具列表
toolMaps.add(mapOf( toolMaps.add(mapOf(
"type" to "function", "type" to "function",
"function" to functionMap "function" to functionMap
@ -325,6 +304,32 @@ class MCPSubClient(
Log.d(TAG, "更新工具映射完成,共 ${toolMaps.size} 个工具") Log.d(TAG, "更新工具映射完成,共 ${toolMaps.size} 个工具")
} }
private fun extractPropertiesContent(schemaStr: String): String? {
val startKey = "properties={"
val startIndex = schemaStr.indexOf(startKey)
if (startIndex == -1) return null
var braceCount = 0
var endIndex = -1
val contentStart = startIndex + startKey.length
for (i in contentStart until schemaStr.length) {
when (schemaStr[i]) {
'{' -> braceCount++
'}' -> {
if (braceCount == 0) {
endIndex = i
break
} else {
braceCount--
}
}
}
}
return if (endIndex != -1) schemaStr.substring(contentStart, endIndex) else null
}
/** /**
* 将JsonNode转换为Map * 将JsonNode转换为Map
*/ */

Loading…
Cancel
Save