v0.1.4版本 #2
348
host/Gateway.cs
348
host/Gateway.cs
@ -229,6 +229,27 @@ public class Gateway
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static (string Matched, string Remaining) ExtractMatchedPart(string input, string toolPattern)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(input) || string.IsNullOrEmpty(toolPattern))
|
||||||
|
return (string.Empty, input);
|
||||||
|
|
||||||
|
Regex regex = new Regex(toolPattern);
|
||||||
|
Match match = regex.Match(input);
|
||||||
|
|
||||||
|
if (!match.Success)
|
||||||
|
return (string.Empty, input);
|
||||||
|
|
||||||
|
string matched = match.Value;
|
||||||
|
int startIndex = match.Index;
|
||||||
|
int length = match.Length;
|
||||||
|
|
||||||
|
// 构造剩余字符串
|
||||||
|
string remaining = input.Substring(0, startIndex) + input.Substring(startIndex + length);
|
||||||
|
|
||||||
|
return (matched, remaining);
|
||||||
|
}
|
||||||
|
|
||||||
public static async void SendMessageStream(string message, string model, string gdbPath, Action<MessageListItem> callback)
|
public static async void SendMessageStream(string message, string model, string gdbPath, Action<MessageListItem> callback)
|
||||||
{
|
{
|
||||||
Llm bailian = new Bailian
|
Llm bailian = new Bailian
|
||||||
@ -249,8 +270,8 @@ public class Gateway
|
|||||||
Content = message
|
Content = message
|
||||||
});
|
});
|
||||||
goOn = true;
|
goOn = true;
|
||||||
string toolPattern = "^<tool_use>[\\s\\S]*?<\\/tool_use>$";
|
string toolPattern = "<tool_use>([\\s\\S]*?)<name>([\\s\\S]*?)<\\/name>([\\s\\S]*?)<arguments>([\\s\\S]*?)<\\/arguments>([\\s\\S]*?)<\\/tool_use>";
|
||||||
string promptPattern = "^<prompt>[\\s\\S]*?<\\/prompt>$";
|
string promptPattern = "<prompt>([\\s\\S]*?)<name>([\\s\\S]*?)<\\/name>([\\s\\S]*?)<\\/prompt>";
|
||||||
McpServerList mcpServerList = new McpServerList();
|
McpServerList mcpServerList = new McpServerList();
|
||||||
int loop = 0;
|
int loop = 0;
|
||||||
while (goOn)
|
while (goOn)
|
||||||
@ -270,169 +291,49 @@ public class Gateway
|
|||||||
MaxTokens = 1000,
|
MaxTokens = 1000,
|
||||||
};
|
};
|
||||||
long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||||
string messageContent = "";
|
string messageContent = ""; //一次请求下完整的response
|
||||||
|
var (toolMatched, toolRemaining) = ExtractMatchedPart(messageContent, toolPattern);
|
||||||
|
var (promptMatched, promptRemaining) = ExtractMatchedPart(messageContent, promptPattern);
|
||||||
|
if (toolMatched == "" && promptMatched == "" && messageContent != "")
|
||||||
|
{
|
||||||
|
//如果本次回复不包含任何工具的调用或提示词的调用,则不再请求
|
||||||
|
break;
|
||||||
|
}
|
||||||
await foreach(var chunk in bailian.SendChatStreamAsync(jsonContent))
|
await foreach(var chunk in bailian.SendChatStreamAsync(jsonContent))
|
||||||
{
|
{
|
||||||
if (chunk == "[DONE]")
|
if (!goOn)
|
||||||
{
|
{
|
||||||
goOn = false;
|
break;
|
||||||
}else if (chunk.StartsWith("<tool_use>"))
|
}
|
||||||
|
var (matched, remaining) = ExtractMatchedPart(chunk, toolPattern);
|
||||||
|
if (matched == "")
|
||||||
{
|
{
|
||||||
if (Regex.IsMatch(chunk, toolPattern))
|
var (matchedPrompt, remainingPrompt) = ExtractMatchedPart(chunk, promptPattern);
|
||||||
|
if (matchedPrompt == "")
|
||||||
{
|
{
|
||||||
//返回工具卡片
|
//普通消息文本
|
||||||
messages.Add(new Message
|
MessageListItem chatMessageListItem = new ChatMessageItem()
|
||||||
{
|
{
|
||||||
Role = "assistant",
|
content = remainingPrompt,
|
||||||
Content = chunk
|
role = "assistant",
|
||||||
});
|
type = MessageType.CHAT_MESSAGE,
|
||||||
XElement toolUse = XElement.Parse(chunk);
|
id = timestamp.ToString()
|
||||||
string fullToolName = toolUse.Element("name")?.Value;
|
};
|
||||||
string toolArgs = toolUse.Element("arguments")?.Value;
|
messageContent = remainingPrompt;
|
||||||
Dictionary<string, object> toolParams = JsonConvert.DeserializeObject<Dictionary<string, object>>(toolArgs);
|
callback?.Invoke(chatMessageListItem);
|
||||||
string serverName = fullToolName.Contains(":") ? fullToolName.Split(':')[0] : fullToolName;
|
|
||||||
string toolName = fullToolName.Contains(":") ? fullToolName.Split(':')[1] : fullToolName;
|
|
||||||
McpServer mcpServer = mcpServerList.GetServer(serverName);
|
|
||||||
if (mcpServer is SseMcpServer)
|
|
||||||
{
|
|
||||||
SseMcpServer sseMcpServer = mcpServer as SseMcpServer;
|
|
||||||
SseMcpClient client = new SseMcpClient(sseMcpServer.BaseUrl);
|
|
||||||
CallToolResponse toolResponse = await client.CallToolAsync(toolName,toolParams);
|
|
||||||
MessageListItem toolMessageItem = new ToolMessageItem
|
|
||||||
{
|
|
||||||
toolName = toolName,
|
|
||||||
toolParams = toolParams,
|
|
||||||
type = MessageType.TOOL_MESSAGE,
|
|
||||||
status = toolResponse.IsError ? "fail" : "success",
|
|
||||||
content = JsonConvert.SerializeObject(toolResponse),
|
|
||||||
id = timestamp.ToString()
|
|
||||||
};
|
|
||||||
messages.Add(new Message
|
|
||||||
{
|
|
||||||
Role = "user",
|
|
||||||
// Content = toolResponse.IsError ? SystemPrompt.ErrorPromptTemplate : SystemPrompt.ContinuePromptTemplate
|
|
||||||
Content = toolResponse.IsError ? SystemPrompt.ErrorPromptTemplate : SystemPrompt.ContinuePrompt(JsonConvert.SerializeObject(toolResponse))
|
|
||||||
});
|
|
||||||
// messages.Add(new Message
|
|
||||||
// {
|
|
||||||
// Role = "user",
|
|
||||||
// Content = JsonConvert.SerializeObject(toolResponse)
|
|
||||||
// });
|
|
||||||
callback?.Invoke(toolMessageItem);
|
|
||||||
}else if (mcpServer is StdioMcpServer)
|
|
||||||
{
|
|
||||||
StdioMcpServer stdioMcpServer = mcpServer as StdioMcpServer;
|
|
||||||
StdioMcpClient client = new StdioMcpClient(stdioMcpServer.Command, stdioMcpServer.Args);
|
|
||||||
CallToolResponse toolResponse = await client.CallToolAsync(toolName,toolParams);
|
|
||||||
MessageListItem toolMessageItem = new ToolMessageItem
|
|
||||||
{
|
|
||||||
toolName = toolName,
|
|
||||||
toolParams = toolParams,
|
|
||||||
type = MessageType.TOOL_MESSAGE,
|
|
||||||
status = toolResponse.IsError ? "fail" : "success",
|
|
||||||
content = JsonConvert.SerializeObject(toolResponse),
|
|
||||||
id = timestamp.ToString()
|
|
||||||
};
|
|
||||||
messages.Add(new Message
|
|
||||||
{
|
|
||||||
Role = "user",
|
|
||||||
// Content = toolResponse.IsError ? SystemPrompt.ErrorPromptTemplate : SystemPrompt.ContinuePromptTemplate
|
|
||||||
Content = toolResponse.IsError ? SystemPrompt.ErrorPromptTemplate : SystemPrompt.ContinuePrompt(JsonConvert.SerializeObject(toolResponse))
|
|
||||||
});
|
|
||||||
// messages.Add(new Message
|
|
||||||
// {
|
|
||||||
// Role = "user",
|
|
||||||
// Content = JsonConvert.SerializeObject(toolResponse)
|
|
||||||
// });
|
|
||||||
callback?.Invoke(toolMessageItem);
|
|
||||||
}else if (mcpServer is InnerMcpServer)
|
|
||||||
{
|
|
||||||
Type type = Type.GetType("LinkToolAddin.client.tool."+serverName);
|
|
||||||
MethodInfo method = type.GetMethod(toolName,BindingFlags.Public | BindingFlags.Static);
|
|
||||||
var methodParams = toolParams.Values.ToArray();
|
|
||||||
object[] args = new object[methodParams.Length];
|
|
||||||
for (int i = 0; i < methodParams.Length; i++)
|
|
||||||
{
|
|
||||||
if (methodParams[i].GetType() == typeof(JArray))
|
|
||||||
{
|
|
||||||
List<string> list = new List<string>();
|
|
||||||
list = (methodParams[i] as JArray).Select(token => token.ToString()).ToList();
|
|
||||||
args[i] = list;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
args[i] = methodParams[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var task = method.Invoke(null, args) as Task<JsonRpcResultEntity>;
|
|
||||||
JsonRpcResultEntity innerResult = await task;
|
|
||||||
if (innerResult is JsonRpcErrorEntity)
|
|
||||||
{
|
|
||||||
MessageListItem toolMessageItem = new ToolMessageItem
|
|
||||||
{
|
|
||||||
toolName = toolName,
|
|
||||||
toolParams = toolParams,
|
|
||||||
type = MessageType.TOOL_MESSAGE,
|
|
||||||
status = "fail",
|
|
||||||
content = JsonConvert.SerializeObject(innerResult),
|
|
||||||
id = timestamp.ToString()
|
|
||||||
};
|
|
||||||
messages.Add(new Message
|
|
||||||
{
|
|
||||||
Role = "user",
|
|
||||||
Content = SystemPrompt.ErrorPromptTemplate
|
|
||||||
});
|
|
||||||
messages.Add(new Message
|
|
||||||
{
|
|
||||||
Role = "user",
|
|
||||||
Content = JsonConvert.SerializeObject(innerResult)
|
|
||||||
});
|
|
||||||
callback?.Invoke(toolMessageItem);
|
|
||||||
}else if (innerResult is JsonRpcSuccessEntity)
|
|
||||||
{
|
|
||||||
MessageListItem toolMessageItem = new ToolMessageItem
|
|
||||||
{
|
|
||||||
toolName = toolName,
|
|
||||||
toolParams = toolParams,
|
|
||||||
type = MessageType.TOOL_MESSAGE,
|
|
||||||
status = "success",
|
|
||||||
content = JsonConvert.SerializeObject(innerResult),
|
|
||||||
id = timestamp.ToString()
|
|
||||||
};
|
|
||||||
messages.Add(new Message
|
|
||||||
{
|
|
||||||
Role = "user",
|
|
||||||
// Content = SystemPrompt.ContinuePromptTemplate
|
|
||||||
Content = SystemPrompt.ContinuePrompt(JsonConvert.SerializeObject(innerResult))
|
|
||||||
});
|
|
||||||
// messages.Add(new Message
|
|
||||||
// {
|
|
||||||
// Role = "user",
|
|
||||||
// Content = JsonConvert.SerializeObject(innerResult)
|
|
||||||
// });
|
|
||||||
callback?.Invoke(toolMessageItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MessageListItem toolMessageItem = new ToolMessageItem
|
//包含Prompt调用请求的消息
|
||||||
|
MessageListItem chatMessageListItem = new ChatMessageItem()
|
||||||
{
|
{
|
||||||
toolName = "",
|
content = remainingPrompt,
|
||||||
toolParams = new Dictionary<string, object>(),
|
role = "assistant",
|
||||||
type = MessageType.TOOL_MESSAGE,
|
type = MessageType.CHAT_MESSAGE,
|
||||||
status = "loading",
|
|
||||||
content = "正在生成工具调用参数",
|
|
||||||
id = timestamp.ToString()
|
id = timestamp.ToString()
|
||||||
};
|
};
|
||||||
callback?.Invoke(toolMessageItem);
|
callback?.Invoke(chatMessageListItem);
|
||||||
continue;
|
XElement promptUse = XElement.Parse(matchedPrompt);
|
||||||
}
|
|
||||||
}else if (chunk.StartsWith("<prompt>"))
|
|
||||||
{
|
|
||||||
if (Regex.IsMatch(chunk, promptPattern))
|
|
||||||
{
|
|
||||||
XElement promptUse = XElement.Parse(chunk);
|
|
||||||
string promptKey = promptUse.Element("name")?.Value;
|
string promptKey = promptUse.Element("name")?.Value;
|
||||||
string promptContent = DynamicPrompt.GetPrompt(promptKey,null);
|
string promptContent = DynamicPrompt.GetPrompt(promptKey,null);
|
||||||
messages.Add(new Message
|
messages.Add(new Message
|
||||||
@ -446,49 +347,134 @@ public class Gateway
|
|||||||
toolParams = null,
|
toolParams = null,
|
||||||
type = MessageType.TOOL_MESSAGE,
|
type = MessageType.TOOL_MESSAGE,
|
||||||
status = "success",
|
status = "success",
|
||||||
content = promptKey,
|
content = "成功调用提示词:"+promptKey,
|
||||||
id = timestamp.ToString()
|
id = (timestamp+1).ToString()
|
||||||
};
|
|
||||||
callback?.Invoke(toolMessageItem);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MessageListItem toolMessageItem = new ToolMessageItem
|
|
||||||
{
|
|
||||||
toolName = "调用提示词",
|
|
||||||
toolParams = null,
|
|
||||||
type = MessageType.TOOL_MESSAGE,
|
|
||||||
status = "loading",
|
|
||||||
content = "正在调用提示词",
|
|
||||||
id = timestamp.ToString()
|
|
||||||
};
|
};
|
||||||
callback?.Invoke(toolMessageItem);
|
callback?.Invoke(toolMessageItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string content = chunk;
|
//包含工具调用请求的消息
|
||||||
if (content.EndsWith("[DONE]"))
|
|
||||||
{
|
|
||||||
content = content.Substring(0, content.Length - 6);
|
|
||||||
}
|
|
||||||
//普通流式消息卡片
|
|
||||||
MessageListItem chatMessageListItem = new ChatMessageItem()
|
MessageListItem chatMessageListItem = new ChatMessageItem()
|
||||||
{
|
{
|
||||||
content = content,
|
content = remaining,
|
||||||
role = "assistant",
|
role = "assistant",
|
||||||
type = MessageType.CHAT_MESSAGE,
|
type = MessageType.CHAT_MESSAGE,
|
||||||
id = timestamp.ToString()
|
id = timestamp.ToString()
|
||||||
};
|
};
|
||||||
messageContent = content;
|
|
||||||
callback?.Invoke(chatMessageListItem);
|
callback?.Invoke(chatMessageListItem);
|
||||||
|
XElement toolUse = XElement.Parse(matched);
|
||||||
|
string fullToolName = toolUse.Element("name")?.Value;
|
||||||
|
string toolArgs = toolUse.Element("arguments")?.Value;
|
||||||
|
Dictionary<string, object> toolParams = JsonConvert.DeserializeObject<Dictionary<string, object>>(toolArgs);
|
||||||
|
string serverName = fullToolName.Contains(":") ? fullToolName.Split(':')[0] : fullToolName;
|
||||||
|
string toolName = fullToolName.Contains(":") ? fullToolName.Split(':')[1] : fullToolName;
|
||||||
|
McpServer mcpServer = mcpServerList.GetServer(serverName);
|
||||||
|
if (mcpServer is SseMcpServer)
|
||||||
|
{
|
||||||
|
SseMcpServer sseMcpServer = mcpServer as SseMcpServer;
|
||||||
|
SseMcpClient client = new SseMcpClient(sseMcpServer.BaseUrl);
|
||||||
|
CallToolResponse toolResponse = await client.CallToolAsync(toolName,toolParams);
|
||||||
|
MessageListItem toolMessageItem = new ToolMessageItem
|
||||||
|
{
|
||||||
|
toolName = toolName,
|
||||||
|
toolParams = toolParams,
|
||||||
|
type = MessageType.TOOL_MESSAGE,
|
||||||
|
status = toolResponse.IsError ? "fail" : "success",
|
||||||
|
content = JsonConvert.SerializeObject(toolResponse),
|
||||||
|
id = (timestamp+1).ToString()
|
||||||
|
};
|
||||||
|
messages.Add(new Message
|
||||||
|
{
|
||||||
|
Role = "user",
|
||||||
|
Content = toolResponse.IsError ? SystemPrompt.ErrorPromptTemplate : SystemPrompt.ContinuePrompt(JsonConvert.SerializeObject(toolResponse))
|
||||||
|
});
|
||||||
|
callback?.Invoke(toolMessageItem);
|
||||||
|
}else if (mcpServer is StdioMcpServer)
|
||||||
|
{
|
||||||
|
StdioMcpServer stdioMcpServer = mcpServer as StdioMcpServer;
|
||||||
|
StdioMcpClient client = new StdioMcpClient(stdioMcpServer.Command, stdioMcpServer.Args);
|
||||||
|
CallToolResponse toolResponse = await client.CallToolAsync(toolName,toolParams);
|
||||||
|
MessageListItem toolMessageItem = new ToolMessageItem
|
||||||
|
{
|
||||||
|
toolName = toolName,
|
||||||
|
toolParams = toolParams,
|
||||||
|
type = MessageType.TOOL_MESSAGE,
|
||||||
|
status = toolResponse.IsError ? "fail" : "success",
|
||||||
|
content = JsonConvert.SerializeObject(toolResponse),
|
||||||
|
id = (timestamp+1).ToString()
|
||||||
|
};
|
||||||
|
messages.Add(new Message
|
||||||
|
{
|
||||||
|
Role = "user",
|
||||||
|
Content = toolResponse.IsError ? SystemPrompt.ErrorPromptTemplate : SystemPrompt.ContinuePrompt(JsonConvert.SerializeObject(toolResponse))
|
||||||
|
});
|
||||||
|
callback?.Invoke(toolMessageItem);
|
||||||
|
}else if (mcpServer is InnerMcpServer)
|
||||||
|
{
|
||||||
|
Type type = Type.GetType("LinkToolAddin.client.tool."+serverName);
|
||||||
|
MethodInfo method = type.GetMethod(toolName,BindingFlags.Public | BindingFlags.Static);
|
||||||
|
var methodParams = toolParams.Values.ToArray();
|
||||||
|
object[] args = new object[methodParams.Length];
|
||||||
|
for (int i = 0; i < methodParams.Length; i++)
|
||||||
|
{
|
||||||
|
if (methodParams[i].GetType() == typeof(JArray))
|
||||||
|
{
|
||||||
|
List<string> list = new List<string>();
|
||||||
|
list = (methodParams[i] as JArray).Select(token => token.ToString()).ToList();
|
||||||
|
args[i] = list;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args[i] = methodParams[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var task = method.Invoke(null, args) as Task<JsonRpcResultEntity>;
|
||||||
|
JsonRpcResultEntity innerResult = await task;
|
||||||
|
if (innerResult is JsonRpcErrorEntity)
|
||||||
|
{
|
||||||
|
MessageListItem toolMessageItem = new ToolMessageItem
|
||||||
|
{
|
||||||
|
toolName = toolName,
|
||||||
|
toolParams = toolParams,
|
||||||
|
type = MessageType.TOOL_MESSAGE,
|
||||||
|
status = "fail",
|
||||||
|
content = JsonConvert.SerializeObject(innerResult),
|
||||||
|
id = (timestamp+1).ToString()
|
||||||
|
};
|
||||||
|
messages.Add(new Message
|
||||||
|
{
|
||||||
|
Role = "user",
|
||||||
|
Content = SystemPrompt.ErrorPromptTemplate
|
||||||
|
});
|
||||||
|
messages.Add(new Message
|
||||||
|
{
|
||||||
|
Role = "user",
|
||||||
|
Content = JsonConvert.SerializeObject(innerResult)
|
||||||
|
});
|
||||||
|
callback?.Invoke(toolMessageItem);
|
||||||
|
}else if (innerResult is JsonRpcSuccessEntity)
|
||||||
|
{
|
||||||
|
MessageListItem toolMessageItem = new ToolMessageItem
|
||||||
|
{
|
||||||
|
toolName = toolName,
|
||||||
|
toolParams = toolParams,
|
||||||
|
type = MessageType.TOOL_MESSAGE,
|
||||||
|
status = "success",
|
||||||
|
content = JsonConvert.SerializeObject(innerResult),
|
||||||
|
id = (timestamp+1).ToString()
|
||||||
|
};
|
||||||
|
messages.Add(new Message
|
||||||
|
{
|
||||||
|
Role = "user",
|
||||||
|
Content = SystemPrompt.ContinuePrompt(JsonConvert.SerializeObject(innerResult))
|
||||||
|
});
|
||||||
|
callback?.Invoke(toolMessageItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
messages.Add(new Message
|
|
||||||
{
|
|
||||||
Role = "assistant",
|
|
||||||
Content = messageContent
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user