first commit
commit
75f016659e
|
@ -0,0 +1,106 @@
|
|||
# Extensions
|
||||
|
||||
*.a
|
||||
*.bat
|
||||
*.bin
|
||||
*.d
|
||||
*.dll
|
||||
*.dot
|
||||
*.etag
|
||||
*.exe
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.gcov
|
||||
*.gguf
|
||||
*.gguf.json
|
||||
*.lastModified
|
||||
*.log
|
||||
*.metallib
|
||||
*.o
|
||||
*.so
|
||||
*.tmp
|
||||
|
||||
# IDE / OS
|
||||
|
||||
.cache/
|
||||
.ccls-cache/
|
||||
.direnv/
|
||||
.DS_Store
|
||||
.envrc
|
||||
.idea/
|
||||
.swiftpm
|
||||
.vs/
|
||||
.vscode/
|
||||
nppBackup
|
||||
|
||||
|
||||
# Coverage
|
||||
|
||||
gcovr-report/
|
||||
lcov-report/
|
||||
|
||||
# Build Artifacts
|
||||
|
||||
tags
|
||||
.build/
|
||||
build*
|
||||
!build-info.cmake
|
||||
!build-info.cpp.in
|
||||
!build-info.sh
|
||||
!build.zig
|
||||
!docs/build.md
|
||||
/libllama.so
|
||||
/llama-*
|
||||
/vulkan-shaders-gen
|
||||
android-ndk-*
|
||||
arm_neon.h
|
||||
cmake-build-*
|
||||
CMakeSettings.json
|
||||
compile_commands.json
|
||||
ggml-metal-embed.metal
|
||||
llama-batched-swift
|
||||
/rpc-server
|
||||
out/
|
||||
tmp/
|
||||
autogen-*.md
|
||||
|
||||
# CI
|
||||
|
||||
!.github/workflows/*.yml
|
||||
|
||||
# Models
|
||||
|
||||
models/*
|
||||
models-mnt
|
||||
!models/.editorconfig
|
||||
|
||||
# Zig
|
||||
|
||||
# Logs
|
||||
|
||||
|
||||
|
||||
# Examples
|
||||
|
||||
|
||||
# Server Web UI temporary files
|
||||
node_modules
|
||||
examples/server/webui/dist
|
||||
|
||||
# Python
|
||||
|
||||
/.venv
|
||||
__pycache__/
|
||||
*/poetry.lock
|
||||
poetry.toml
|
||||
|
||||
# Nix
|
||||
/result
|
||||
|
||||
# Test binaries
|
||||
|
||||
# Scripts
|
||||
|
||||
# Test models for lora adapters
|
||||
|
||||
# Local scripts
|
|
@ -0,0 +1,44 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
project(OpenManusCpp VERSION 0.1.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# 查找OpenSSL库,尝试查找3.0.0版本,但如果找不到,也接受其他版本
|
||||
find_package(OpenSSL REQUIRED)
|
||||
if(OPENSSL_FOUND)
|
||||
message(STATUS "OpenSSL found: ${OPENSSL_VERSION}")
|
||||
message(STATUS "OpenSSL include directory: ${OPENSSL_INCLUDE_DIR}")
|
||||
message(STATUS "OpenSSL libraries: ${OPENSSL_LIBRARIES}")
|
||||
include_directories(${OPENSSL_INCLUDE_DIR})
|
||||
add_compile_definitions(CPPHTTPLIB_OPENSSL_SUPPORT)
|
||||
else()
|
||||
message(FATAL_ERROR "OpenSSL not found. Please install OpenSSL development libraries.")
|
||||
endif()
|
||||
|
||||
# 添加MCP库
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/mcp)
|
||||
|
||||
# 添加包含目录
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/mcp/include)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/mcp/common)
|
||||
|
||||
# 查找必要的包
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# 添加源文件
|
||||
file(GLOB_RECURSE SOURCES
|
||||
"src/*.cpp"
|
||||
"src/*.cc"
|
||||
)
|
||||
|
||||
# 添加可执行文件
|
||||
add_executable(openmanus_cpp ${SOURCES} main.cpp)
|
||||
|
||||
# 链接库
|
||||
target_link_libraries(openmanus_cpp PRIVATE Threads::Threads mcp ${OPENSSL_LIBRARIES})
|
||||
|
||||
# 安装目标
|
||||
install(TARGETS openmanus_cpp DESTINATION bin)
|
|
@ -0,0 +1,204 @@
|
|||
# OpenManus C++版本
|
||||
|
||||
这是OpenManus项目的C++实现版本,旨在提供与原始Python版本相同的功能。
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
cpp/
|
||||
├── include/ # 头文件目录
|
||||
│ ├── agent_base.h # 代理基类
|
||||
│ ├── manus.h # Manus代理
|
||||
│ ├── tool_base.h # 工具基类
|
||||
│ ├── tool_call.h # 工具调用类
|
||||
│ ├── tool_call_agent.h # 工具调用代理
|
||||
│ ├── tool_collection.h # 工具集合类
|
||||
│ ├── flow/ # 流程头文件目录
|
||||
│ │ ├── base_flow.h # 流程基类
|
||||
│ │ ├── planning_flow.h # 规划流程
|
||||
│ │ └── flow_factory.h # 流程工厂
|
||||
│ └── tools/ # 工具头文件目录
|
||||
│ └── terminate.h # 终止工具
|
||||
├── src/ # 源文件目录
|
||||
│ ├── agent_base.cpp # 代理基类实现
|
||||
│ ├── manus.cpp # Manus代理实现
|
||||
│ ├── tool_base.cpp # 工具基类实现
|
||||
│ ├── tool_call.cpp # 工具调用类实现
|
||||
│ ├── tool_call_agent.cpp # 工具调用代理实现
|
||||
│ ├── tool_collection.cpp # 工具集合类实现
|
||||
│ ├── flow/ # 流程实现目录
|
||||
│ │ ├── base_flow.cpp # 流程基类实现
|
||||
│ │ ├── planning_flow.cpp # 规划流程实现
|
||||
│ │ └── flow_factory.cpp # 流程工厂实现
|
||||
│ └── tools/ # 工具实现目录
|
||||
│ └── terminate.cpp # 终止工具实现
|
||||
├── server/ # MCP服务器目录
|
||||
│ ├── mcp_server_main.cpp # MCP服务器主程序
|
||||
│ └── CMakeLists.txt # 服务器构建文件
|
||||
├── main.cpp # 主程序入口
|
||||
├── mcp/ # MCP协议库
|
||||
└── CMakeLists.txt # CMake构建文件
|
||||
```
|
||||
|
||||
## 已完成工作
|
||||
|
||||
1. **基础框架搭建**
|
||||
- 创建了基本的项目结构和CMakeLists.txt文件
|
||||
- 实现了基础代理类(AgentBase)
|
||||
- 实现了工具集合类(ToolCollection)
|
||||
- 实现了工具基类(ToolBase)
|
||||
- 实现了工具调用类(ToolCall)
|
||||
- 实现了工具调用代理类(ToolCallAgent)
|
||||
- 实现了Manus代理类
|
||||
|
||||
2. **流程层实现**
|
||||
- 实现了流程基类(BaseFlow)
|
||||
- 实现了规划流程(PlanningFlow)
|
||||
- 实现了流程工厂(FlowFactory)
|
||||
- 修改了主程序,使用流程层执行任务
|
||||
|
||||
3. **工具实现**
|
||||
- 实现了终止工具(Terminate),用于终止代理执行
|
||||
- 实现了Python执行工具(PythonExecute),可以执行Python代码
|
||||
|
||||
4. **MCP服务器**
|
||||
- 实现了基本的MCP服务器
|
||||
- 实现了PythonExecute工具,可以执行Python代码
|
||||
|
||||
5. **LLM集成**
|
||||
- 使用httplib.h实现了与LLM API的通信
|
||||
- 实现了think方法,能够调用LLM API获取下一步行动
|
||||
- 实现了工具调用的解析和执行
|
||||
- 添加了Authorization头部,支持API密钥认证
|
||||
|
||||
6. **配置系统**
|
||||
- 实现了TOML格式的配置文件读取
|
||||
- 支持从配置文件中读取LLM API、工具和代理等参数
|
||||
- 支持在运行时指定配置文件路径
|
||||
|
||||
7. **编译与运行**
|
||||
- 成功编译并运行了基本框架
|
||||
- 解决了与MCP协议库的集成问题
|
||||
|
||||
## 未完成工作
|
||||
|
||||
1. **工具实现**
|
||||
- Google搜索工具(GoogleSearch)
|
||||
- 浏览器使用工具(BrowserUseTool)
|
||||
- 文件保存工具(FileSaver)
|
||||
- 其他工具...
|
||||
|
||||
2. **LLM集成完善**
|
||||
- 添加更多的LLM模型支持
|
||||
- 实现流式响应处理
|
||||
- 添加更多的提示模板
|
||||
|
||||
3. **MCP协议完整集成**
|
||||
- 完善客户端与MCP服务器的通信
|
||||
- 实现完整的请求-响应流程
|
||||
|
||||
4. **错误处理与日志**
|
||||
- 添加更完善的错误处理机制
|
||||
- 实现日志记录功能
|
||||
|
||||
5. **测试与文档**
|
||||
- 编写单元测试
|
||||
- 编写集成测试
|
||||
- 完善API文档
|
||||
|
||||
## 配置文件
|
||||
|
||||
OpenManus使用TOML格式的配置文件来配置LLM API、工具和代理等参数。默认配置文件为`config.toml`,位于可执行文件所在目录。
|
||||
|
||||
### 配置文件示例
|
||||
|
||||
```toml
|
||||
# OpenManus配置文件
|
||||
|
||||
[llm]
|
||||
# LLM API主机
|
||||
host = "localhost"
|
||||
# LLM API端口
|
||||
port = 8000
|
||||
# LLM API路径
|
||||
path = "/chat/completions"
|
||||
# LLM API密钥
|
||||
api_key = "your_api_key_here"
|
||||
# LLM模型名称
|
||||
model = "gpt-3.5-turbo"
|
||||
# 是否启用流式响应
|
||||
stream = false
|
||||
|
||||
[tools]
|
||||
# 是否启用Python执行工具
|
||||
enable_python_execute = true
|
||||
# 是否启用Google搜索工具
|
||||
enable_google_search = false
|
||||
# 是否启用浏览器使用工具
|
||||
enable_browser_use = false
|
||||
# 是否启用文件保存工具
|
||||
enable_file_saver = false
|
||||
|
||||
[agent]
|
||||
# 最大步骤数
|
||||
max_steps = 30
|
||||
# 系统提示
|
||||
system_prompt = "你是Manus,一个通用的智能助手,可以使用多种工具解决各种任务。"
|
||||
# 下一步提示
|
||||
next_step_prompt = "请思考下一步行动,使用可用的工具来解决用户的问题。"
|
||||
```
|
||||
|
||||
### 运行时指定配置文件
|
||||
|
||||
可以在运行时通过命令行参数指定配置文件路径:
|
||||
|
||||
```bash
|
||||
./openmanus_cpp /path/to/your/config.toml
|
||||
```
|
||||
|
||||
## 构建与运行
|
||||
|
||||
### 构建主程序
|
||||
|
||||
```bash
|
||||
cd cpp
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
```
|
||||
|
||||
### 运行主程序
|
||||
|
||||
```bash
|
||||
./openmanus_cpp
|
||||
```
|
||||
|
||||
### 构建MCP服务器
|
||||
|
||||
```bash
|
||||
cd cpp/server
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
```
|
||||
|
||||
### 运行MCP服务器
|
||||
|
||||
```bash
|
||||
./openmanus_mcp_server
|
||||
```
|
||||
|
||||
## 依赖
|
||||
|
||||
- C++17
|
||||
- CMake 3.10+
|
||||
- nlohmann/json (包含在mcp/common目录中)
|
||||
- httplib.h (包含在项目中)
|
||||
- Python 3 (用于PythonExecute工具)
|
||||
- LLM API服务 (如OpenAI API或本地部署的LLM服务)
|
||||
|
||||
## 许可证
|
||||
|
||||
与原始OpenManus项目相同的许可证。
|
|
@ -0,0 +1,14 @@
|
|||
[llm]
|
||||
model = "deepseek-chat"
|
||||
base_url = "https://api.deepseek.com"
|
||||
api_key = "sk-93c5bfcb920c4a8aa345791d429b8536"
|
||||
max_tokens = 4096
|
||||
provider = "openrouter"
|
||||
|
||||
[agent]
|
||||
# 最大步骤数
|
||||
max_steps = 30
|
||||
# 最大连续工具调用次数
|
||||
max_consecutive_tool_calls = 10
|
||||
# 是否每次运行都清空历史
|
||||
clear_history_each_run = false
|
|
@ -0,0 +1,18 @@
|
|||
[llm]
|
||||
model = "deepseek-chat"
|
||||
base_url = "https://api.deepseek.com"
|
||||
api_key = "sk-93c5bfcb920c4a8aa345791d429b8536"
|
||||
max_tokens = 4096
|
||||
provider = "openrouter"
|
||||
|
||||
[agent]
|
||||
# 最大步骤数
|
||||
max_steps = 30
|
||||
# 最大连续工具调用次数
|
||||
max_consecutive_tool_calls = 10
|
||||
# 系统提示
|
||||
system_prompt = "你是Manus,一个通用的智能助手,可以使用多种工具解决各种任务。你可以使用规划工具来创建和管理结构化计划,使用Python执行工具来执行Python代码。请注意以下重要规则:\n1. 你最多只能连续调用工具5次,超过限制将被强制停止。\n2. 当任务完成时,你必须调用Terminate工具来结束执行。\n3. 如果你已经获得了足够的信息来回答用户的问题,请提供答案,然后调用Terminate工具。\n4. 不要无限循环调用工具,确保每次工具调用都有明确的目的。"
|
||||
# 下一步提示
|
||||
next_step_prompt = "请思考下一步行动,使用可用的工具来解决用户的问题。如果你已经获得了足够的信息,请直接回答问题,然后调用Terminate工具来结束执行。记住,任务完成后必须调用Terminate工具。"
|
||||
# 是否每次运行都清空历史
|
||||
clear_history_each_run = false
|
|
@ -0,0 +1,58 @@
|
|||
#ifndef OPENMANUS_AGENT_BASE_H
|
||||
#define OPENMANUS_AGENT_BASE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "tool_collection.h"
|
||||
#include "mcp/include/mcp_message.h"
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
/**
|
||||
* @class AgentBase
|
||||
* @brief 代理的基类,定义了所有代理的基本接口
|
||||
*/
|
||||
class AgentBase : public std::enable_shared_from_this<AgentBase> {
|
||||
public:
|
||||
AgentBase(const std::string& name, const std::string& description);
|
||||
virtual ~AgentBase() = default;
|
||||
|
||||
/**
|
||||
* @brief 运行代理,处理用户输入的提示
|
||||
* @param prompt 用户输入的提示
|
||||
* @return 处理结果
|
||||
*/
|
||||
virtual std::string run(const std::string& prompt) = 0;
|
||||
|
||||
/**
|
||||
* @brief 执行工具调用
|
||||
* @param tool_name 工具名称
|
||||
* @param params 工具参数
|
||||
* @return 执行结果
|
||||
*/
|
||||
virtual mcp::json executeToolCall(const std::string& tool_name, const mcp::json& params);
|
||||
|
||||
/**
|
||||
* @brief 获取代理名称
|
||||
* @return 代理名称
|
||||
*/
|
||||
std::string getName() const { return name_; }
|
||||
|
||||
/**
|
||||
* @brief 获取代理描述
|
||||
* @return 代理描述
|
||||
*/
|
||||
std::string getDescription() const { return description_; }
|
||||
|
||||
protected:
|
||||
std::string name_;
|
||||
std::string description_;
|
||||
std::string system_prompt_;
|
||||
std::string next_step_prompt_;
|
||||
std::unique_ptr<ToolCollection> available_tools_;
|
||||
};
|
||||
|
||||
} // namespace openmanus
|
||||
|
||||
#endif // OPENMANUS_AGENT_BASE_H
|
|
@ -0,0 +1,72 @@
|
|||
#ifndef OPENMANUS_CONFIG_H
|
||||
#define OPENMANUS_CONFIG_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
/**
|
||||
* @class Config
|
||||
* @brief 配置文件读取类,用于读取TOML格式的配置文件
|
||||
*/
|
||||
class Config {
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
* @param config_file 配置文件路径
|
||||
*/
|
||||
Config(const std::string& config_file = "config.toml");
|
||||
|
||||
/**
|
||||
* @brief 加载配置文件
|
||||
* @param config_file 配置文件路径
|
||||
* @return 是否加载成功
|
||||
*/
|
||||
bool load(const std::string& config_file);
|
||||
|
||||
/**
|
||||
* @brief 获取字符串配置项
|
||||
* @param section 配置节
|
||||
* @param key 配置键
|
||||
* @param default_value 默认值
|
||||
* @return 配置值
|
||||
*/
|
||||
std::string getString(const std::string& section, const std::string& key, const std::string& default_value = "") const;
|
||||
|
||||
/**
|
||||
* @brief 获取整数配置项
|
||||
* @param section 配置节
|
||||
* @param key 配置键
|
||||
* @param default_value 默认值
|
||||
* @return 配置值
|
||||
*/
|
||||
int getInt(const std::string& section, const std::string& key, int default_value = 0) const;
|
||||
|
||||
/**
|
||||
* @brief 获取浮点数配置项
|
||||
* @param section 配置节
|
||||
* @param key 配置键
|
||||
* @param default_value 默认值
|
||||
* @return 配置值
|
||||
*/
|
||||
double getDouble(const std::string& section, const std::string& key, double default_value = 0.0) const;
|
||||
|
||||
/**
|
||||
* @brief 获取布尔配置项
|
||||
* @param section 配置节
|
||||
* @param key 配置键
|
||||
* @param default_value 默认值
|
||||
* @return 配置值
|
||||
*/
|
||||
bool getBool(const std::string& section, const std::string& key, bool default_value = false) const;
|
||||
|
||||
private:
|
||||
std::map<std::string, std::map<std::string, std::string>> config_data_;
|
||||
};
|
||||
|
||||
} // namespace openmanus
|
||||
|
||||
#endif // OPENMANUS_CONFIG_H
|
|
@ -0,0 +1,77 @@
|
|||
#ifndef OPENMANUS_FLOW_BASE_FLOW_H
|
||||
#define OPENMANUS_FLOW_BASE_FLOW_H
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include "../agent_base.h"
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
/**
|
||||
* @enum FlowType
|
||||
* @brief 流程类型枚举
|
||||
*/
|
||||
enum class FlowType {
|
||||
PLANNING
|
||||
};
|
||||
|
||||
/**
|
||||
* @class BaseFlow
|
||||
* @brief 执行流程的基类,支持多个代理
|
||||
*/
|
||||
class BaseFlow {
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
* @param agent 主要代理
|
||||
*/
|
||||
BaseFlow(std::shared_ptr<AgentBase> agent);
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
* @param agents 多个代理
|
||||
*/
|
||||
BaseFlow(const std::vector<std::shared_ptr<AgentBase>>& agents);
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
virtual ~BaseFlow() = default;
|
||||
|
||||
/**
|
||||
* @brief 执行流程
|
||||
* @param input_text 输入文本
|
||||
* @return 执行结果
|
||||
*/
|
||||
virtual std::string execute(const std::string& input_text) = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取主要代理
|
||||
* @return 主要代理
|
||||
*/
|
||||
std::shared_ptr<AgentBase> getPrimaryAgent() const;
|
||||
|
||||
/**
|
||||
* @brief 获取指定代理
|
||||
* @param key 代理键
|
||||
* @return 代理
|
||||
*/
|
||||
std::shared_ptr<AgentBase> getAgent(const std::string& key) const;
|
||||
|
||||
/**
|
||||
* @brief 添加代理
|
||||
* @param key 代理键
|
||||
* @param agent 代理
|
||||
*/
|
||||
void addAgent(const std::string& key, std::shared_ptr<AgentBase> agent);
|
||||
|
||||
protected:
|
||||
std::unordered_map<std::string, std::shared_ptr<AgentBase>> agents_;
|
||||
std::string primary_agent_key_;
|
||||
};
|
||||
|
||||
} // namespace openmanus
|
||||
|
||||
#endif // OPENMANUS_FLOW_BASE_FLOW_H
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef OPENMANUS_FLOW_FLOW_FACTORY_H
|
||||
#define OPENMANUS_FLOW_FLOW_FACTORY_H
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "base_flow.h"
|
||||
#include "planning_flow.h"
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
/**
|
||||
* @class FlowFactory
|
||||
* @brief 流程工厂,用于创建不同类型的流程
|
||||
*/
|
||||
class FlowFactory {
|
||||
public:
|
||||
/**
|
||||
* @brief 创建流程
|
||||
* @param flow_type 流程类型
|
||||
* @param agent 主要代理
|
||||
* @return 流程
|
||||
*/
|
||||
static std::shared_ptr<BaseFlow> createFlow(
|
||||
FlowType flow_type,
|
||||
std::shared_ptr<AgentBase> agent
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief 创建流程
|
||||
* @param flow_type 流程类型
|
||||
* @param agents 多个代理
|
||||
* @return 流程
|
||||
*/
|
||||
static std::shared_ptr<BaseFlow> createFlow(
|
||||
FlowType flow_type,
|
||||
const std::vector<std::shared_ptr<AgentBase>>& agents
|
||||
);
|
||||
};
|
||||
|
||||
} // namespace openmanus
|
||||
|
||||
#endif // OPENMANUS_FLOW_FLOW_FACTORY_H
|
|
@ -0,0 +1,64 @@
|
|||
#ifndef OPENMANUS_FLOW_PLANNING_FLOW_H
|
||||
#define OPENMANUS_FLOW_PLANNING_FLOW_H
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include "base_flow.h"
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
/**
|
||||
* @class PlanningFlow
|
||||
* @brief 规划流程,使用规划代理执行任务
|
||||
*/
|
||||
class PlanningFlow : public BaseFlow {
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
* @param agent 主要代理
|
||||
*/
|
||||
PlanningFlow(std::shared_ptr<AgentBase> agent);
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
* @param agents 多个代理
|
||||
*/
|
||||
PlanningFlow(const std::vector<std::shared_ptr<AgentBase>>& agents);
|
||||
|
||||
/**
|
||||
* @brief 执行流程
|
||||
* @param input_text 输入文本
|
||||
* @return 执行结果
|
||||
*/
|
||||
virtual std::string execute(const std::string& input_text) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 获取当前计划状态
|
||||
* @return 计划状态
|
||||
*/
|
||||
std::string getPlanStatus();
|
||||
|
||||
/**
|
||||
* @brief 更新步骤执行状态
|
||||
* @param step_id 步骤ID
|
||||
* @param status 状态
|
||||
* @return 是否成功
|
||||
*/
|
||||
bool updateStepStatus(const std::string& step_id, const std::string& status);
|
||||
|
||||
/**
|
||||
* @brief 获取当前步骤索引
|
||||
* @return 当前步骤索引
|
||||
*/
|
||||
int getCurrentStepIndex();
|
||||
|
||||
private:
|
||||
std::string active_plan_id_;
|
||||
std::unordered_map<std::string, std::unordered_map<std::string, std::string>> step_execution_tracker_;
|
||||
};
|
||||
|
||||
} // namespace openmanus
|
||||
|
||||
#endif // OPENMANUS_FLOW_PLANNING_FLOW_H
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef OPENMANUS_MANUS_H
|
||||
#define OPENMANUS_MANUS_H
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "tool_call_agent.h"
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
/**
|
||||
* @class Manus
|
||||
* @brief Manus代理,一个通用的智能助手
|
||||
*/
|
||||
class Manus : public ToolCallAgent {
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
* @param config_file 配置文件路径
|
||||
*/
|
||||
Manus(const std::string& config_file = "config.toml");
|
||||
virtual ~Manus() = default;
|
||||
|
||||
/**
|
||||
* @brief 初始化代理
|
||||
*/
|
||||
void initialize();
|
||||
|
||||
private:
|
||||
// 添加特定于Manus的工具
|
||||
void addManusTools();
|
||||
};
|
||||
|
||||
} // namespace openmanus
|
||||
|
||||
#endif // OPENMANUS_MANUS_H
|
|
@ -0,0 +1,54 @@
|
|||
#ifndef OPENMANUS_TOOL_BASE_H
|
||||
#define OPENMANUS_TOOL_BASE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include "mcp/include/mcp_message.h"
|
||||
#include "mcp/include/mcp_tool.h"
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
/**
|
||||
* @class ToolBase
|
||||
* @brief 工具的基类,定义了所有工具的基本接口
|
||||
*/
|
||||
class ToolBase {
|
||||
public:
|
||||
ToolBase(const std::string& name, const std::string& description);
|
||||
virtual ~ToolBase() = default;
|
||||
|
||||
/**
|
||||
* @brief 执行工具
|
||||
* @param params 工具参数
|
||||
* @return 执行结果
|
||||
*/
|
||||
virtual mcp::json execute(const mcp::json& params) = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取工具名称
|
||||
* @return 工具名称
|
||||
*/
|
||||
std::string getName() const { return name_; }
|
||||
|
||||
/**
|
||||
* @brief 获取工具描述
|
||||
* @return 工具描述
|
||||
*/
|
||||
std::string getDescription() const { return description_; }
|
||||
|
||||
/**
|
||||
* @brief 获取工具参数定义
|
||||
* @return 参数定义
|
||||
*/
|
||||
mcp::json getParameters() const { return parameters_; }
|
||||
|
||||
protected:
|
||||
std::string name_;
|
||||
std::string description_;
|
||||
mcp::json parameters_; // 参数定义,使用JSON Schema格式
|
||||
};
|
||||
|
||||
} // namespace openmanus
|
||||
|
||||
#endif // OPENMANUS_TOOL_BASE_H
|
|
@ -0,0 +1,70 @@
|
|||
#ifndef OPENMANUS_TOOL_CALL_H
|
||||
#define OPENMANUS_TOOL_CALL_H
|
||||
|
||||
#include <string>
|
||||
#include "mcp/include/mcp_message.h"
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
/**
|
||||
* @class ToolCall
|
||||
* @brief 工具调用类,表示一次工具调用
|
||||
*/
|
||||
class ToolCall {
|
||||
public:
|
||||
ToolCall(const std::string& id, const std::string& name, const mcp::json& params);
|
||||
~ToolCall() = default;
|
||||
|
||||
/**
|
||||
* @brief 获取工具调用ID
|
||||
* @return 工具调用ID
|
||||
*/
|
||||
std::string getId() const { return id_; }
|
||||
|
||||
/**
|
||||
* @brief 获取工具名称
|
||||
* @return 工具名称
|
||||
*/
|
||||
std::string getName() const { return name_; }
|
||||
|
||||
/**
|
||||
* @brief 获取工具参数
|
||||
* @return 工具参数
|
||||
*/
|
||||
mcp::json getParams() const { return params_; }
|
||||
|
||||
/**
|
||||
* @brief 设置执行结果
|
||||
* @param result 执行结果
|
||||
*/
|
||||
void setResult(const std::string& result) { result_ = result; }
|
||||
|
||||
/**
|
||||
* @brief 获取执行结果
|
||||
* @return 执行结果
|
||||
*/
|
||||
std::string getResult() const { return result_; }
|
||||
|
||||
/**
|
||||
* @brief 从JSON对象创建工具调用
|
||||
* @param json JSON对象
|
||||
* @return 工具调用对象
|
||||
*/
|
||||
static ToolCall fromJson(const mcp::json& json);
|
||||
|
||||
/**
|
||||
* @brief 转换为JSON对象
|
||||
* @return JSON对象
|
||||
*/
|
||||
mcp::json toJson() const;
|
||||
|
||||
private:
|
||||
std::string id_; // 工具调用ID
|
||||
std::string name_; // 工具名称
|
||||
mcp::json params_; // 工具参数
|
||||
std::string result_; // 执行结果
|
||||
};
|
||||
|
||||
} // namespace openmanus
|
||||
|
||||
#endif // OPENMANUS_TOOL_CALL_H
|
|
@ -0,0 +1,179 @@
|
|||
#ifndef OPENMANUS_TOOL_CALL_AGENT_H
|
||||
#define OPENMANUS_TOOL_CALL_AGENT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "agent_base.h"
|
||||
#include "tool_call.h"
|
||||
#include "config.h"
|
||||
#include "mcp/common/httplib.h"
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
// 消息类型枚举
|
||||
enum class MessageRole {
|
||||
SYSTEM,
|
||||
USER,
|
||||
ASSISTANT,
|
||||
TOOL
|
||||
};
|
||||
|
||||
// 消息结构体
|
||||
struct Message {
|
||||
MessageRole role;
|
||||
std::string content;
|
||||
std::string name; // 用于工具消息的工具名称
|
||||
std::string tool_call_id; // 用于工具消息的工具调用ID
|
||||
|
||||
// 创建系统消息
|
||||
static Message systemMessage(const std::string& content) {
|
||||
return {MessageRole::SYSTEM, content, "", ""};
|
||||
}
|
||||
|
||||
// 创建用户消息
|
||||
static Message userMessage(const std::string& content) {
|
||||
return {MessageRole::USER, content, "", ""};
|
||||
}
|
||||
|
||||
// 创建助手消息
|
||||
static Message assistantMessage(const std::string& content) {
|
||||
return {MessageRole::ASSISTANT, content, "", ""};
|
||||
}
|
||||
|
||||
// 创建工具消息
|
||||
static Message toolMessage(const std::string& content, const std::string& name, const std::string& tool_call_id) {
|
||||
return {MessageRole::TOOL, content, name, tool_call_id};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class ToolCallAgent
|
||||
* @brief 工具调用代理,能够执行工具调用的代理
|
||||
*/
|
||||
class ToolCallAgent : public AgentBase {
|
||||
public:
|
||||
ToolCallAgent(const std::string& name, const std::string& description, const std::string& config_file = "config.toml");
|
||||
virtual ~ToolCallAgent() = default;
|
||||
|
||||
/**
|
||||
* @brief 运行代理,处理用户输入的提示
|
||||
* @param prompt 用户输入的提示
|
||||
* @return 处理结果
|
||||
*/
|
||||
virtual std::string run(const std::string& prompt) override;
|
||||
|
||||
/**
|
||||
* @brief 设置LLM API参数
|
||||
* @param host LLM API主机
|
||||
* @param port LLM API端口
|
||||
* @param endpoint LLM API端点
|
||||
*/
|
||||
void setLLMAPIParams(const std::string& host, int port, const std::string& endpoint);
|
||||
|
||||
/**
|
||||
* @brief 设置云服务提供商的LLM API参数
|
||||
* @param provider 提供商名称(如"deepseek")
|
||||
* @param base_url 基础URL
|
||||
* @param endpoint API端点
|
||||
*/
|
||||
void setCloudLLMAPIParams(const std::string& provider, const std::string& base_url, const std::string& endpoint);
|
||||
|
||||
/**
|
||||
* @brief 设置LLM API密钥
|
||||
* @param api_key LLM API密钥
|
||||
*/
|
||||
void setLLMAPIKey(const std::string& api_key);
|
||||
|
||||
/**
|
||||
* @brief 清空消息历史
|
||||
*/
|
||||
void clearMessages();
|
||||
|
||||
/**
|
||||
* @brief 添加消息到历史
|
||||
* @param message 消息
|
||||
*/
|
||||
void addMessage(const Message& message);
|
||||
|
||||
/**
|
||||
* @brief 获取消息历史
|
||||
* @return 消息历史
|
||||
*/
|
||||
const std::vector<Message>& getMessages() const { return messages_; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief 思考下一步行动
|
||||
* @return 是否继续执行
|
||||
*/
|
||||
virtual bool think();
|
||||
|
||||
/**
|
||||
* @brief 执行行动
|
||||
* @return 执行结果
|
||||
*/
|
||||
virtual std::string act();
|
||||
|
||||
/**
|
||||
* @brief 执行工具
|
||||
* @param tool_call 工具调用
|
||||
* @return 执行结果
|
||||
*/
|
||||
virtual std::string executeToolCall(const ToolCall& tool_call);
|
||||
|
||||
/**
|
||||
* @brief 处理特殊工具
|
||||
* @param name 工具名称
|
||||
* @param result 执行结果
|
||||
* @return 是否是特殊工具
|
||||
*/
|
||||
virtual bool handleSpecialTool(const std::string& name, const std::string& result);
|
||||
|
||||
/**
|
||||
* @brief 判断是否应该结束执行
|
||||
* @return 是否结束执行
|
||||
*/
|
||||
virtual bool shouldFinishExecution();
|
||||
|
||||
/**
|
||||
* @brief 判断是否是特殊工具
|
||||
* @param name 工具名称
|
||||
* @return 是否是特殊工具
|
||||
*/
|
||||
virtual bool isSpecialTool(const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief 调用LLM API获取下一步行动
|
||||
* @param messages 消息历史
|
||||
* @return 响应JSON
|
||||
*/
|
||||
virtual mcp::json callLLMAPI(const std::vector<Message>& messages);
|
||||
|
||||
protected:
|
||||
std::vector<Message> messages_; // 消息历史
|
||||
std::vector<ToolCall> tool_calls_; // 工具调用列表
|
||||
int max_steps_; // 最大步骤数
|
||||
int current_step_; // 当前步骤
|
||||
bool should_clear_history_; // 是否应该清空历史
|
||||
int max_consecutive_tool_calls_; // 最大连续工具调用次数
|
||||
int consecutive_tool_calls_; // 当前连续工具调用次数
|
||||
|
||||
// 配置
|
||||
Config config_; // 配置
|
||||
|
||||
// LLM API相关
|
||||
std::string llm_api_host_; // LLM API主机
|
||||
int llm_api_port_; // LLM API端口
|
||||
std::string llm_api_base_url_; // LLM API基础URL
|
||||
std::string llm_api_endpoint_; // LLM API端点
|
||||
std::string llm_api_key_; // LLM API密钥
|
||||
std::string llm_model_; // LLM模型名称
|
||||
int llm_max_tokens_; // LLM最大生成token数
|
||||
std::string llm_provider_; // LLM提供商
|
||||
std::unique_ptr<httplib::Client> http_client_; // HTTP客户端
|
||||
};
|
||||
|
||||
} // namespace openmanus
|
||||
|
||||
#endif // OPENMANUS_TOOL_CALL_AGENT_H
|
|
@ -0,0 +1,52 @@
|
|||
#ifndef OPENMANUS_TOOL_COLLECTION_H
|
||||
#define OPENMANUS_TOOL_COLLECTION_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include "tool_base.h"
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
/**
|
||||
* @class ToolCollection
|
||||
* @brief 工具集合类,管理所有可用的工具
|
||||
*/
|
||||
class ToolCollection {
|
||||
public:
|
||||
ToolCollection();
|
||||
~ToolCollection() = default;
|
||||
|
||||
/**
|
||||
* @brief 添加工具到集合中
|
||||
* @param tool 要添加的工具
|
||||
*/
|
||||
void addTool(std::unique_ptr<ToolBase> tool);
|
||||
|
||||
/**
|
||||
* @brief 根据名称获取工具
|
||||
* @param name 工具名称
|
||||
* @return 工具指针,如果不存在则返回nullptr
|
||||
*/
|
||||
ToolBase* getTool(const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief 获取所有工具的名称
|
||||
* @return 工具名称列表
|
||||
*/
|
||||
std::vector<std::string> getToolNames() const;
|
||||
|
||||
/**
|
||||
* @brief 获取工具数量
|
||||
* @return 工具数量
|
||||
*/
|
||||
size_t size() const { return tools_.size(); }
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, std::unique_ptr<ToolBase>> tools_;
|
||||
};
|
||||
|
||||
} // namespace openmanus
|
||||
|
||||
#endif // OPENMANUS_TOOL_COLLECTION_H
|
|
@ -0,0 +1,73 @@
|
|||
#ifndef OPENMANUS_TOOLS_PLANNING_H
|
||||
#define OPENMANUS_TOOLS_PLANNING_H
|
||||
|
||||
#include "../tool_base.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
/**
|
||||
* @class Planning
|
||||
* @brief 规划工具,用于创建和管理结构化计划
|
||||
*/
|
||||
class Planning : public ToolBase {
|
||||
public:
|
||||
Planning();
|
||||
virtual ~Planning() = default;
|
||||
|
||||
/**
|
||||
* @brief 执行规划工具
|
||||
* @param params 工具参数
|
||||
* @return 执行结果
|
||||
*/
|
||||
virtual mcp::json execute(const mcp::json& params) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 创建新计划
|
||||
* @param params 参数
|
||||
* @return 结果
|
||||
*/
|
||||
mcp::json createPlan(const mcp::json& params);
|
||||
|
||||
/**
|
||||
* @brief 获取计划状态
|
||||
* @param params 参数
|
||||
* @return 结果
|
||||
*/
|
||||
mcp::json getPlanStatus(const mcp::json& params);
|
||||
|
||||
/**
|
||||
* @brief 更新步骤状态
|
||||
* @param params 参数
|
||||
* @return 结果
|
||||
*/
|
||||
mcp::json updateStepStatus(const mcp::json& params);
|
||||
|
||||
/**
|
||||
* @brief 添加步骤
|
||||
* @param params 参数
|
||||
* @return 结果
|
||||
*/
|
||||
mcp::json addStep(const mcp::json& params);
|
||||
|
||||
private:
|
||||
// 计划结构
|
||||
struct Plan {
|
||||
std::string id;
|
||||
std::string title;
|
||||
std::string description;
|
||||
std::vector<std::string> step_ids;
|
||||
std::unordered_map<std::string, std::string> step_descriptions;
|
||||
std::unordered_map<std::string, std::string> step_statuses;
|
||||
int current_step_index;
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, Plan> plans_;
|
||||
};
|
||||
|
||||
} // namespace openmanus
|
||||
|
||||
#endif // OPENMANUS_TOOLS_PLANNING_H
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef OPENMANUS_TOOLS_PYTHON_EXECUTE_H
|
||||
#define OPENMANUS_TOOLS_PYTHON_EXECUTE_H
|
||||
|
||||
#include "../tool_base.h"
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
/**
|
||||
* @class PythonExecute
|
||||
* @brief Python执行工具,用于执行Python代码
|
||||
*/
|
||||
class PythonExecute : public ToolBase {
|
||||
public:
|
||||
PythonExecute();
|
||||
virtual ~PythonExecute() = default;
|
||||
|
||||
/**
|
||||
* @brief 执行Python代码
|
||||
* @param params 工具参数,包含code字段
|
||||
* @return 执行结果
|
||||
*/
|
||||
virtual mcp::json execute(const mcp::json& params) override;
|
||||
};
|
||||
|
||||
} // namespace openmanus
|
||||
|
||||
#endif // OPENMANUS_TOOLS_PYTHON_EXECUTE_H
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef OPENMANUS_TOOLS_TERMINATE_H
|
||||
#define OPENMANUS_TOOLS_TERMINATE_H
|
||||
|
||||
#include "../tool_base.h"
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
/**
|
||||
* @class Terminate
|
||||
* @brief 终止工具,用于终止代理的执行
|
||||
*/
|
||||
class Terminate : public ToolBase {
|
||||
public:
|
||||
Terminate();
|
||||
virtual ~Terminate() = default;
|
||||
|
||||
/**
|
||||
* @brief 执行终止工具
|
||||
* @param params 工具参数
|
||||
* @return 执行结果
|
||||
*/
|
||||
virtual mcp::json execute(const mcp::json& params) override;
|
||||
};
|
||||
|
||||
} // namespace openmanus
|
||||
|
||||
#endif // OPENMANUS_TOOLS_TERMINATE_H
|
|
@ -0,0 +1,72 @@
|
|||
#include <iostream>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "include/manus.h"
|
||||
#include "include/flow/flow_factory.h"
|
||||
#include "include/config.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
try {
|
||||
// 获取配置文件路径
|
||||
std::string config_file = "config.toml";
|
||||
if (argc > 1) {
|
||||
config_file = argv[1];
|
||||
}
|
||||
|
||||
std::cout << "使用配置文件: " << config_file << std::endl;
|
||||
|
||||
// 创建Manus代理实例
|
||||
auto agent = std::make_shared<openmanus::Manus>(config_file);
|
||||
|
||||
// 读取配置文件
|
||||
openmanus::Config config(config_file);
|
||||
std::string provider = config.getString("llm", "provider", "local");
|
||||
|
||||
// 根据提供商设置LLM API参数
|
||||
if (provider == "local") {
|
||||
std::string host = config.getString("llm", "host", "localhost");
|
||||
int port = config.getInt("llm", "port", 8000);
|
||||
std::string path = config.getString("llm", "path", "/chat/completions");
|
||||
agent->setLLMAPIParams(host, port, path);
|
||||
} else {
|
||||
std::string base_url = config.getString("llm", "base_url", "");
|
||||
std::string path = config.getString("llm", "path", "/v1/chat/completions");
|
||||
agent->setCloudLLMAPIParams(provider, base_url, path);
|
||||
}
|
||||
|
||||
// 设置API密钥
|
||||
std::string api_key = config.getString("llm", "api_key", "");
|
||||
if (!api_key.empty()) {
|
||||
agent->setLLMAPIKey(api_key);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
std::string prompt;
|
||||
std::cout << "输入你的提示 (或输入 'exit' 退出): ";
|
||||
std::getline(std::cin, prompt);
|
||||
|
||||
if (prompt == "exit") {
|
||||
std::cout << "再见!" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
std::cout << "正在处理你的请求..." << std::endl;
|
||||
|
||||
// 创建规划流程
|
||||
auto flow = openmanus::FlowFactory::createFlow(
|
||||
openmanus::FlowType::PLANNING,
|
||||
agent
|
||||
);
|
||||
|
||||
// 执行流程
|
||||
std::string result = flow->execute(prompt);
|
||||
|
||||
std::cout << "处理结果: " << result << std::endl;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "错误: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 175d66864253ab305d57524ca58edc4ecffb2ec9
|
|
@ -0,0 +1,37 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
project(OpenManusMCPServer VERSION 0.1.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# 查找OpenSSL库
|
||||
find_package(OpenSSL REQUIRED)
|
||||
if(OPENSSL_FOUND)
|
||||
message(STATUS "OpenSSL found: ${OPENSSL_VERSION}")
|
||||
message(STATUS "OpenSSL include directory: ${OPENSSL_INCLUDE_DIR}")
|
||||
message(STATUS "OpenSSL libraries: ${OPENSSL_LIBRARIES}")
|
||||
include_directories(${OPENSSL_INCLUDE_DIR})
|
||||
add_compile_definitions(CPPHTTPLIB_OPENSSL_SUPPORT)
|
||||
else()
|
||||
message(FATAL_ERROR "OpenSSL not found. Please install OpenSSL development libraries.")
|
||||
endif()
|
||||
|
||||
# 添加MCP库
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../mcp ${CMAKE_CURRENT_BINARY_DIR}/mcp)
|
||||
|
||||
# 添加包含目录
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../mcp/include)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../mcp/common)
|
||||
|
||||
# 查找必要的包
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# 添加可执行文件
|
||||
add_executable(openmanus_mcp_server mcp_server_main.cpp)
|
||||
|
||||
# 链接库
|
||||
target_link_libraries(openmanus_mcp_server PRIVATE Threads::Threads mcp ${OPENSSL_LIBRARIES})
|
||||
|
||||
# 安装目标
|
||||
install(TARGETS openmanus_mcp_server DESTINATION bin)
|
|
@ -0,0 +1,123 @@
|
|||
/**
|
||||
* @file mcp_server_main.cpp
|
||||
* @brief OpenManus MCP服务器实现
|
||||
*
|
||||
* 这个文件实现了OpenManus的MCP服务器,提供工具调用功能。
|
||||
* 当前实现了PythonExecute工具。
|
||||
*/
|
||||
|
||||
#include "mcp/include/mcp_server.h"
|
||||
#include "mcp/include/mcp_tool.h"
|
||||
#include "mcp/include/mcp_resource.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <filesystem>
|
||||
#include <cstdio>
|
||||
#include <array>
|
||||
#include <stdexcept>
|
||||
|
||||
// 执行系统命令并返回输出
|
||||
std::string exec_command(const std::string& cmd) {
|
||||
std::array<char, 128> buffer;
|
||||
std::string result;
|
||||
|
||||
// 打开管道,执行命令
|
||||
FILE* pipe = popen(cmd.c_str(), "r");
|
||||
if (!pipe) {
|
||||
throw std::runtime_error("popen() failed!");
|
||||
}
|
||||
|
||||
// 读取命令输出
|
||||
while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) {
|
||||
result += buffer.data();
|
||||
}
|
||||
|
||||
// 关闭管道
|
||||
int status = pclose(pipe);
|
||||
if (status == -1) {
|
||||
throw std::runtime_error("pclose() failed!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// PythonExecute工具处理函数
|
||||
mcp::json python_execute_handler(const mcp::json& args) {
|
||||
if (!args.contains("code")) {
|
||||
std::cout << args.dump() << std::endl;
|
||||
throw mcp::mcp_exception(mcp::error_code::invalid_params, "缺少'code'参数");
|
||||
}
|
||||
|
||||
std::string code = args["code"];
|
||||
|
||||
// 创建临时Python文件
|
||||
std::string temp_file = "/tmp/openmanus_temp.py";
|
||||
|
||||
// 写入Python代码到临时文件
|
||||
std::ofstream out(temp_file);
|
||||
if (!out) {
|
||||
throw mcp::mcp_exception(mcp::error_code::internal_error, "无法创建临时Python文件");
|
||||
}
|
||||
out << code;
|
||||
out.close();
|
||||
|
||||
try {
|
||||
// 执行Python代码
|
||||
std::string cmd = "python3 " + temp_file + " 2>&1";
|
||||
std::string output = exec_command(cmd);
|
||||
|
||||
// 删除临时文件
|
||||
std::filesystem::remove(temp_file);
|
||||
|
||||
if (output.empty()) {
|
||||
output = "Executed successfully but w/o output. Maybe you should print more information.";
|
||||
}
|
||||
|
||||
return {{
|
||||
{"type", "text"},
|
||||
{"text", output}
|
||||
}};
|
||||
} catch (const std::exception& e) {
|
||||
// 删除临时文件
|
||||
std::filesystem::remove(temp_file);
|
||||
|
||||
throw mcp::mcp_exception(mcp::error_code::internal_error,
|
||||
"执行Python代码失败: " + std::string(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
// 创建并配置服务器
|
||||
mcp::server server("localhost", 8080);
|
||||
server.set_server_info("OpenManusMCPServer", "2024-11-05");
|
||||
|
||||
// 设置服务器能力
|
||||
mcp::json capabilities = {
|
||||
{"tools", {{"listChanged", true}}},
|
||||
{"resources", {{"listChanged", true}}}
|
||||
};
|
||||
server.set_capabilities(capabilities);
|
||||
|
||||
// 注册方法处理函数
|
||||
server.register_method("ping", [](const mcp::json& params) {
|
||||
return mcp::json{{"pong", true}};
|
||||
});
|
||||
|
||||
// 注册PythonExecute工具
|
||||
mcp::tool python_tool = mcp::tool_builder("PythonExecute")
|
||||
.with_description("执行Python代码并返回结果")
|
||||
.with_string_param("code", "要执行的Python代码", true)
|
||||
.build();
|
||||
|
||||
server.register_tool(python_tool, python_execute_handler);
|
||||
|
||||
// 启动服务器
|
||||
std::cout << "启动OpenManus MCP服务器,地址: localhost:8080..." << std::endl;
|
||||
std::cout << "按Ctrl+C停止服务器" << std::endl;
|
||||
server.start(true); // 阻塞模式
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#include "include/agent_base.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
AgentBase::AgentBase(const std::string& name, const std::string& description)
|
||||
: name_(name), description_(description) {
|
||||
// 初始化工具集合
|
||||
available_tools_ = std::make_unique<ToolCollection>();
|
||||
}
|
||||
|
||||
mcp::json AgentBase::executeToolCall(const std::string& tool_name, const mcp::json& params) {
|
||||
// 获取工具
|
||||
ToolBase* tool = available_tools_->getTool(tool_name);
|
||||
if (!tool) {
|
||||
throw std::runtime_error("找不到工具: " + tool_name);
|
||||
}
|
||||
|
||||
// 执行工具
|
||||
return tool->execute(params);
|
||||
}
|
||||
|
||||
} // namespace openmanus
|
|
@ -0,0 +1,117 @@
|
|||
#include "include/config.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
Config::Config(const std::string& config_file) {
|
||||
load(config_file);
|
||||
}
|
||||
|
||||
bool Config::load(const std::string& config_file) {
|
||||
std::ifstream file(config_file);
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "无法打开配置文件: " << config_file << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
std::string current_section;
|
||||
|
||||
while (std::getline(file, line)) {
|
||||
// 去除前后空白
|
||||
line.erase(0, line.find_first_not_of(" \t"));
|
||||
line.erase(line.find_last_not_of(" \t") + 1);
|
||||
|
||||
// 跳过空行和注释
|
||||
if (line.empty() || line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 处理节
|
||||
if (line[0] == '[' && line[line.length() - 1] == ']') {
|
||||
current_section = line.substr(1, line.length() - 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 处理键值对
|
||||
size_t pos = line.find('=');
|
||||
if (pos != std::string::npos) {
|
||||
std::string key = line.substr(0, pos);
|
||||
std::string value = line.substr(pos + 1);
|
||||
|
||||
// 去除键和值的前后空白
|
||||
key.erase(0, key.find_first_not_of(" \t"));
|
||||
key.erase(key.find_last_not_of(" \t") + 1);
|
||||
value.erase(0, value.find_first_not_of(" \t"));
|
||||
value.erase(value.find_last_not_of(" \t") + 1);
|
||||
|
||||
// 处理引号
|
||||
if (value.length() >= 2 && (value[0] == '"' && value[value.length() - 1] == '"' ||
|
||||
value[0] == '\'' && value[value.length() - 1] == '\'')) {
|
||||
value = value.substr(1, value.length() - 2);
|
||||
}
|
||||
|
||||
config_data_[current_section][key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Config::getString(const std::string& section, const std::string& key, const std::string& default_value) const {
|
||||
auto section_it = config_data_.find(section);
|
||||
if (section_it != config_data_.end()) {
|
||||
auto key_it = section_it->second.find(key);
|
||||
if (key_it != section_it->second.end()) {
|
||||
return key_it->second;
|
||||
}
|
||||
}
|
||||
return default_value;
|
||||
}
|
||||
|
||||
int Config::getInt(const std::string& section, const std::string& key, int default_value) const {
|
||||
std::string value = getString(section, key, "");
|
||||
if (!value.empty()) {
|
||||
try {
|
||||
return std::stoi(value);
|
||||
} catch (...) {
|
||||
// 转换失败,返回默认值
|
||||
}
|
||||
}
|
||||
return default_value;
|
||||
}
|
||||
|
||||
double Config::getDouble(const std::string& section, const std::string& key, double default_value) const {
|
||||
std::string value = getString(section, key, "");
|
||||
if (!value.empty()) {
|
||||
try {
|
||||
return std::stod(value);
|
||||
} catch (...) {
|
||||
// 转换失败,返回默认值
|
||||
}
|
||||
}
|
||||
return default_value;
|
||||
}
|
||||
|
||||
bool Config::getBool(const std::string& section, const std::string& key, bool default_value) const {
|
||||
std::string value = getString(section, key, "");
|
||||
if (!value.empty()) {
|
||||
// 转换为小写
|
||||
std::transform(value.begin(), value.end(), value.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
|
||||
if (value == "true" || value == "yes" || value == "1") {
|
||||
return true;
|
||||
} else if (value == "false" || value == "no" || value == "0") {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return default_value;
|
||||
}
|
||||
|
||||
} // namespace openmanus
|
|
@ -0,0 +1,50 @@
|
|||
#include "include/flow/base_flow.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
BaseFlow::BaseFlow(std::shared_ptr<AgentBase> agent) {
|
||||
if (agent) {
|
||||
primary_agent_key_ = "default";
|
||||
agents_[primary_agent_key_] = agent;
|
||||
}
|
||||
}
|
||||
|
||||
BaseFlow::BaseFlow(const std::vector<std::shared_ptr<AgentBase>>& agents) {
|
||||
if (!agents.empty()) {
|
||||
primary_agent_key_ = "agent0";
|
||||
for (size_t i = 0; i < agents.size(); ++i) {
|
||||
if (agents[i]) {
|
||||
std::string key = "agent" + std::to_string(i);
|
||||
agents_[key] = agents[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<AgentBase> BaseFlow::getPrimaryAgent() const {
|
||||
auto it = agents_.find(primary_agent_key_);
|
||||
if (it != agents_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<AgentBase> BaseFlow::getAgent(const std::string& key) const {
|
||||
auto it = agents_.find(key);
|
||||
if (it != agents_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void BaseFlow::addAgent(const std::string& key, std::shared_ptr<AgentBase> agent) {
|
||||
if (agent) {
|
||||
agents_[key] = agent;
|
||||
if (agents_.size() == 1) {
|
||||
primary_agent_key_ = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace openmanus
|
|
@ -0,0 +1,30 @@
|
|||
#include "include/flow/flow_factory.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
std::shared_ptr<BaseFlow> FlowFactory::createFlow(
|
||||
FlowType flow_type,
|
||||
std::shared_ptr<AgentBase> agent
|
||||
) {
|
||||
switch (flow_type) {
|
||||
case FlowType::PLANNING:
|
||||
return std::make_shared<PlanningFlow>(agent);
|
||||
default:
|
||||
throw std::runtime_error("未知的流程类型");
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<BaseFlow> FlowFactory::createFlow(
|
||||
FlowType flow_type,
|
||||
const std::vector<std::shared_ptr<AgentBase>>& agents
|
||||
) {
|
||||
switch (flow_type) {
|
||||
case FlowType::PLANNING:
|
||||
return std::make_shared<PlanningFlow>(agents);
|
||||
default:
|
||||
throw std::runtime_error("未知的流程类型");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace openmanus
|
|
@ -0,0 +1,170 @@
|
|||
#include "include/flow/planning_flow.h"
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include "mcp/include/mcp_message.h"
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
PlanningFlow::PlanningFlow(std::shared_ptr<AgentBase> agent)
|
||||
: BaseFlow(agent) {
|
||||
// 生成计划ID
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto now_time_t = std::chrono::system_clock::to_time_t(now);
|
||||
std::stringstream ss;
|
||||
ss << "plan_" << std::put_time(std::localtime(&now_time_t), "%Y%m%d%H%M%S");
|
||||
active_plan_id_ = ss.str();
|
||||
}
|
||||
|
||||
PlanningFlow::PlanningFlow(const std::vector<std::shared_ptr<AgentBase>>& agents)
|
||||
: BaseFlow(agents) {
|
||||
// 生成计划ID
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto now_time_t = std::chrono::system_clock::to_time_t(now);
|
||||
std::stringstream ss;
|
||||
ss << "plan_" << std::put_time(std::localtime(&now_time_t), "%Y%m%d%H%M%S");
|
||||
active_plan_id_ = ss.str();
|
||||
}
|
||||
|
||||
std::string PlanningFlow::execute(const std::string& input_text) {
|
||||
auto primary_agent = getPrimaryAgent();
|
||||
if (!primary_agent) {
|
||||
throw std::runtime_error("没有可用的代理");
|
||||
}
|
||||
|
||||
std::cout << "使用规划流程执行任务..." << std::endl;
|
||||
|
||||
// 构建提示,包含计划状态
|
||||
std::string prompt = "CURRENT PLAN STATUS:\n" + getPlanStatus() + "\n\n" + input_text;
|
||||
|
||||
// 执行主要代理
|
||||
std::string result = primary_agent->run(prompt);
|
||||
|
||||
// 获取当前步骤索引
|
||||
int current_step_index = getCurrentStepIndex();
|
||||
|
||||
// 如果有工具调用,更新步骤状态
|
||||
// 注意:这里假设ToolCallAgent会在执行工具后更新消息历史
|
||||
// 在实际实现中,需要根据具体情况调整
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string PlanningFlow::getPlanStatus() {
|
||||
auto primary_agent = getPrimaryAgent();
|
||||
if (!primary_agent) {
|
||||
return "没有可用的代理";
|
||||
}
|
||||
|
||||
// 构建获取计划状态的参数
|
||||
mcp::json params = {
|
||||
{"action", "get_plan_status"},
|
||||
{"plan_id", active_plan_id_}
|
||||
};
|
||||
|
||||
// 创建工具调用
|
||||
mcp::json tool_call = {
|
||||
{"name", "planning"},
|
||||
{"params", params}
|
||||
};
|
||||
|
||||
try {
|
||||
// 执行工具调用
|
||||
// 注意:这里假设ToolBase有一个静态方法可以执行工具调用
|
||||
// 在实际实现中,需要根据具体情况调整
|
||||
mcp::json result = primary_agent->executeToolCall("planning", params);
|
||||
|
||||
// 解析结果
|
||||
if (result.contains("success") && result["success"].get<bool>()) {
|
||||
if (result.contains("plan")) {
|
||||
return result["plan"].dump(4);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有计划,创建一个新计划
|
||||
if (!result.contains("success") || !result["success"].get<bool>()) {
|
||||
mcp::json create_params = {
|
||||
{"action", "create_plan"},
|
||||
{"plan_id", active_plan_id_},
|
||||
{"title", "任务计划"},
|
||||
{"description", "执行用户请求的任务"}
|
||||
};
|
||||
|
||||
mcp::json create_result = primary_agent->executeToolCall("planning", create_params);
|
||||
|
||||
if (create_result.contains("success") && create_result["success"].get<bool>()) {
|
||||
active_plan_id_ = create_result["plan_id"];
|
||||
|
||||
// 重新获取计划状态
|
||||
return getPlanStatus();
|
||||
}
|
||||
}
|
||||
|
||||
return "无法获取计划状态";
|
||||
} catch (const std::exception& e) {
|
||||
return std::string("获取计划状态出错: ") + e.what();
|
||||
}
|
||||
}
|
||||
|
||||
bool PlanningFlow::updateStepStatus(const std::string& step_id, const std::string& status) {
|
||||
auto primary_agent = getPrimaryAgent();
|
||||
if (!primary_agent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 构建更新步骤状态的参数
|
||||
mcp::json params = {
|
||||
{"action", "update_step_status"},
|
||||
{"plan_id", active_plan_id_},
|
||||
{"step_id", step_id},
|
||||
{"status", status}
|
||||
};
|
||||
|
||||
try {
|
||||
// 执行工具调用
|
||||
mcp::json result = primary_agent->executeToolCall("planning", params);
|
||||
|
||||
// 解析结果
|
||||
if (result.contains("success") && result["success"].get<bool>()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "更新步骤状态出错: " << e.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int PlanningFlow::getCurrentStepIndex() {
|
||||
auto primary_agent = getPrimaryAgent();
|
||||
if (!primary_agent) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 构建获取计划状态的参数
|
||||
mcp::json params = {
|
||||
{"action", "get_plan_status"},
|
||||
{"plan_id", active_plan_id_}
|
||||
};
|
||||
|
||||
try {
|
||||
// 执行工具调用
|
||||
mcp::json result = primary_agent->executeToolCall("planning", params);
|
||||
|
||||
// 解析结果
|
||||
if (result.contains("success") && result["success"].get<bool>()) {
|
||||
if (result.contains("plan") && result["plan"].contains("current_step_index")) {
|
||||
return result["plan"]["current_step_index"];
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "获取当前步骤索引出错: " << e.what() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace openmanus
|
|
@ -0,0 +1,55 @@
|
|||
#include "include/manus.h"
|
||||
#include "include/tools/terminate.h"
|
||||
#include "include/tools/python_execute.h"
|
||||
#include "include/tools/planning.h"
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
Manus::Manus(const std::string& config_file)
|
||||
: ToolCallAgent("Manus", "一个通用的智能助手,可以使用多种工具解决各种任务", config_file) {
|
||||
// 初始化Manus代理
|
||||
initialize();
|
||||
}
|
||||
|
||||
void Manus::initialize() {
|
||||
// 系统提示和下一步提示已经在ToolCallAgent构造函数中从配置文件读取
|
||||
|
||||
// 添加Manus特定的工具
|
||||
addManusTools();
|
||||
}
|
||||
|
||||
void Manus::addManusTools() {
|
||||
// 添加终止工具
|
||||
available_tools_->addTool(std::make_unique<Terminate>());
|
||||
|
||||
// 添加规划工具
|
||||
available_tools_->addTool(std::make_unique<Planning>());
|
||||
|
||||
// 根据配置决定是否添加Python执行工具
|
||||
if (config_.getBool("tools", "enable_python_execute", true)) {
|
||||
available_tools_->addTool(std::make_unique<PythonExecute>());
|
||||
}
|
||||
|
||||
// 在这里添加其他Manus特定的工具
|
||||
// 根据配置决定是否添加其他工具
|
||||
if (config_.getBool("tools", "enable_google_search", false)) {
|
||||
// available_tools_->addTool(std::make_unique<GoogleSearch>());
|
||||
std::cout << "Google搜索工具尚未实现" << std::endl;
|
||||
}
|
||||
|
||||
if (config_.getBool("tools", "enable_browser_use", false)) {
|
||||
// available_tools_->addTool(std::make_unique<BrowserUseTool>());
|
||||
std::cout << "浏览器使用工具尚未实现" << std::endl;
|
||||
}
|
||||
|
||||
if (config_.getBool("tools", "enable_file_saver", false)) {
|
||||
// available_tools_->addTool(std::make_unique<FileSaver>());
|
||||
std::cout << "文件保存工具尚未实现" << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "添加Manus特定的工具..." << std::endl;
|
||||
}
|
||||
|
||||
} // namespace openmanus
|
|
@ -0,0 +1,11 @@
|
|||
#include "include/tool_base.h"
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
ToolBase::ToolBase(const std::string& name, const std::string& description)
|
||||
: name_(name), description_(description) {
|
||||
// 初始化参数定义为空对象
|
||||
parameters_ = mcp::json::object();
|
||||
}
|
||||
|
||||
} // namespace openmanus
|
|
@ -0,0 +1,26 @@
|
|||
#include "include/tool_call.h"
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
ToolCall::ToolCall(const std::string& id, const std::string& name, const mcp::json& params)
|
||||
: id_(id), name_(name), params_(params), result_("") {
|
||||
}
|
||||
|
||||
ToolCall ToolCall::fromJson(const mcp::json& json) {
|
||||
std::string id = json.contains("id") ? json["id"].get<std::string>() : "";
|
||||
std::string name = json.contains("name") ? json["name"].get<std::string>() : "";
|
||||
mcp::json params = json.contains("params") ? json["params"] : mcp::json::object();
|
||||
|
||||
return ToolCall(id, name, params);
|
||||
}
|
||||
|
||||
mcp::json ToolCall::toJson() const {
|
||||
mcp::json json;
|
||||
json["id"] = id_;
|
||||
json["name"] = name_;
|
||||
json["params"] = params_;
|
||||
json["result"] = result_;
|
||||
return json;
|
||||
}
|
||||
|
||||
} // namespace openmanus
|
|
@ -0,0 +1,494 @@
|
|||
#include "include/tool_call_agent.h"
|
||||
#include "mcp/include/mcp_tool.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
ToolCallAgent::ToolCallAgent(const std::string& name, const std::string& description, const std::string& config_file)
|
||||
: AgentBase(name, description), config_(config_file), max_steps_(30), current_step_(0), should_clear_history_(false), max_consecutive_tool_calls_(5), consecutive_tool_calls_(0) {
|
||||
// 从配置文件中读取LLM API相关信息
|
||||
llm_provider_ = config_.getString("llm", "provider", "local");
|
||||
|
||||
if (llm_provider_ == "local") {
|
||||
// 本地服务器配置
|
||||
llm_api_host_ = config_.getString("llm", "host", "localhost");
|
||||
llm_api_port_ = config_.getInt("llm", "port", 8000);
|
||||
llm_api_endpoint_ = config_.getString("llm", "path", "/chat/completions");
|
||||
|
||||
// 初始化HTTP客户端 - 本地服务器
|
||||
http_client_ = std::make_unique<httplib::Client>(llm_api_host_, llm_api_port_);
|
||||
} else {
|
||||
// 云服务提供商配置
|
||||
llm_api_base_url_ = config_.getString("llm", "base_url", "");
|
||||
llm_api_endpoint_ = config_.getString("llm", "path", "/v1/chat/completions");
|
||||
|
||||
// 初始化HTTP客户端 - 云服务
|
||||
http_client_ = std::make_unique<httplib::Client>(llm_api_base_url_);
|
||||
}
|
||||
|
||||
// 通用配置
|
||||
llm_api_key_ = config_.getString("llm", "api_key", "");
|
||||
llm_model_ = config_.getString("llm", "model", "gpt-3.5-turbo");
|
||||
llm_max_tokens_ = config_.getInt("llm", "max_tokens", 4096);
|
||||
|
||||
// 设置HTTP客户端超时
|
||||
http_client_->set_connection_timeout(300); // 设置连接超时时间为5分钟
|
||||
http_client_->set_read_timeout(300); // 设置读取超时时间为5分钟
|
||||
|
||||
// 从配置文件中读取代理相关信息
|
||||
max_steps_ = config_.getInt("agent", "max_steps", 30);
|
||||
max_consecutive_tool_calls_ = config_.getInt("agent", "max_consecutive_tool_calls", 5);
|
||||
system_prompt_ = config_.getString("agent", "system_prompt", "你是一个能够使用工具的智能助手。");
|
||||
next_step_prompt_ = config_.getString("agent", "next_step_prompt", "请思考下一步行动。");
|
||||
should_clear_history_ = config_.getBool("agent", "clear_history_each_run", false);
|
||||
|
||||
// 添加系统提示
|
||||
if (!system_prompt_.empty()) {
|
||||
messages_.push_back(Message::systemMessage(system_prompt_));
|
||||
}
|
||||
}
|
||||
|
||||
void ToolCallAgent::setLLMAPIParams(const std::string& host, int port, const std::string& endpoint) {
|
||||
// 设置为本地服务器模式
|
||||
llm_provider_ = "local";
|
||||
llm_api_host_ = host;
|
||||
llm_api_port_ = port;
|
||||
llm_api_endpoint_ = endpoint;
|
||||
|
||||
// 重新初始化HTTP客户端
|
||||
http_client_ = std::make_unique<httplib::Client>(llm_api_host_, llm_api_port_);
|
||||
http_client_->set_connection_timeout(300); // 设置连接超时时间为5分钟
|
||||
http_client_->set_read_timeout(300); // 设置读取超时时间为5分钟
|
||||
}
|
||||
|
||||
// 新增方法,用于设置云服务提供商的API参数
|
||||
void ToolCallAgent::setCloudLLMAPIParams(const std::string& provider, const std::string& base_url, const std::string& endpoint) {
|
||||
llm_provider_ = provider;
|
||||
llm_api_base_url_ = base_url;
|
||||
llm_api_endpoint_ = endpoint;
|
||||
|
||||
// 重新初始化HTTP客户端
|
||||
http_client_ = std::make_unique<httplib::Client>(llm_api_base_url_);
|
||||
http_client_->set_connection_timeout(300); // 设置连接超时时间为5分钟
|
||||
http_client_->set_read_timeout(300); // 设置读取超时时间为5分钟
|
||||
}
|
||||
|
||||
void ToolCallAgent::setLLMAPIKey(const std::string& api_key) {
|
||||
llm_api_key_ = api_key;
|
||||
}
|
||||
|
||||
void ToolCallAgent::clearMessages() {
|
||||
messages_.clear();
|
||||
|
||||
// 添加系统提示
|
||||
if (!system_prompt_.empty()) {
|
||||
messages_.push_back(Message::systemMessage(system_prompt_));
|
||||
}
|
||||
}
|
||||
|
||||
void ToolCallAgent::addMessage(const Message& message) {
|
||||
messages_.push_back(message);
|
||||
}
|
||||
|
||||
std::string ToolCallAgent::run(const std::string& prompt) {
|
||||
// 清空工具调用
|
||||
tool_calls_.clear();
|
||||
current_step_ = 0;
|
||||
consecutive_tool_calls_ = 0; // 重置连续工具调用计数器
|
||||
|
||||
// 如果配置为每次运行清空历史,则清空
|
||||
if (should_clear_history_) {
|
||||
clearMessages();
|
||||
}
|
||||
|
||||
// 添加用户提示到消息历史
|
||||
addMessage(Message::userMessage(prompt));
|
||||
|
||||
std::string result;
|
||||
bool terminated = false;
|
||||
|
||||
// 执行代理循环
|
||||
while (current_step_ < max_steps_ && !terminated) {
|
||||
// 思考下一步行动
|
||||
bool continue_execution = think();
|
||||
if (!continue_execution) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 检查是否有Terminate工具调用
|
||||
for (const auto& tool_call : tool_calls_) {
|
||||
if (tool_call.getName() == "Terminate") {
|
||||
std::cout << "🛑 检测到Terminate工具调用,将在此步骤后停止执行" << std::endl;
|
||||
terminated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 执行行动
|
||||
result = act();
|
||||
|
||||
// 检查是否应该结束执行
|
||||
if (terminated || shouldFinishExecution()) {
|
||||
break;
|
||||
}
|
||||
|
||||
current_step_++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ToolCallAgent::think() {
|
||||
// 检查连续工具调用次数
|
||||
if (consecutive_tool_calls_ >= max_consecutive_tool_calls_) {
|
||||
std::cout << "⚠️ 达到最大连续工具调用次数限制(" << max_consecutive_tool_calls_ << "),强制停止" << std::endl;
|
||||
|
||||
// 添加一条消息,告知LLM已达到工具调用限制
|
||||
std::string limit_message = "已达到最大连续工具调用次数限制(" + std::to_string(max_consecutive_tool_calls_) +
|
||||
")。请总结目前的进展并提供最终答案,不要再使用工具。";
|
||||
addMessage(Message::userMessage(limit_message));
|
||||
|
||||
// 重置计数器
|
||||
consecutive_tool_calls_ = 0;
|
||||
}
|
||||
|
||||
// 如果有下一步提示,添加到消息历史
|
||||
if (!next_step_prompt_.empty()) {
|
||||
addMessage(Message::userMessage(next_step_prompt_));
|
||||
}
|
||||
|
||||
try {
|
||||
// 调用LLM API获取下一步行动
|
||||
mcp::json response = callLLMAPI(messages_);
|
||||
|
||||
// 解析响应,提取工具调用
|
||||
tool_calls_.clear();
|
||||
|
||||
if (response.contains("choices") && response["choices"].is_array() && !response["choices"].empty()) {
|
||||
auto& choice = response["choices"][0];
|
||||
|
||||
// 记录思考内容
|
||||
std::string content = "";
|
||||
if (choice.contains("message") && choice["message"].contains("content")) {
|
||||
content = choice["message"]["content"].get<std::string>();
|
||||
if (!content.empty()) {
|
||||
std::cout << "✨ " << name_ << "的思考: " << content << std::endl;
|
||||
|
||||
// 添加助手消息到历史
|
||||
addMessage(Message::assistantMessage(content));
|
||||
}
|
||||
}
|
||||
|
||||
// 提取工具调用
|
||||
if (choice.contains("message") && choice["message"].contains("tool_calls") &&
|
||||
choice["message"]["tool_calls"].is_array()) {
|
||||
|
||||
auto& tool_calls_json = choice["message"]["tool_calls"];
|
||||
std::cout << "🛠️ " << name_ << "选择了 " << tool_calls_json.size() << " 个工具使用" << std::endl;
|
||||
|
||||
if (!tool_calls_json.empty()) {
|
||||
std::cout << "🧰 正在准备的工具: ";
|
||||
bool has_terminate = false;
|
||||
|
||||
for (const auto& tool_call_json : tool_calls_json) {
|
||||
if (tool_call_json.contains("id") && tool_call_json.contains("function")) {
|
||||
std::string id = tool_call_json["id"];
|
||||
std::string name = tool_call_json["function"]["name"];
|
||||
|
||||
// 检查是否是Terminate工具
|
||||
if (name == "Terminate") {
|
||||
has_terminate = true;
|
||||
std::cout << "🛑 检测到Terminate工具调用!" << std::endl;
|
||||
}
|
||||
|
||||
mcp::json params = tool_call_json["function"].contains("arguments") ?
|
||||
tool_call_json["function"]["arguments"] : mcp::json::object();
|
||||
|
||||
// 如果参数是字符串,尝试解析为JSON
|
||||
if (params.is_string()) {
|
||||
try {
|
||||
params = mcp::json::parse(params.get<std::string>());
|
||||
} catch (...) {
|
||||
// 如果解析失败,保持原样
|
||||
}
|
||||
}
|
||||
|
||||
// 创建工具调用对象
|
||||
ToolCall tool_call(id, name, params);
|
||||
tool_calls_.push_back(tool_call);
|
||||
|
||||
std::cout << name << " ";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return !tool_calls_.empty();
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "思考过程中出错: " << e.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mcp::json ToolCallAgent::callLLMAPI(const std::vector<Message>& messages) {
|
||||
// 构建请求JSON
|
||||
mcp::json request;
|
||||
|
||||
// 根据不同的LLM提供商构建不同的请求
|
||||
if (llm_provider_ == "deepseek") {
|
||||
// DeepSeek API请求格式
|
||||
request["model"] = llm_model_;
|
||||
request["messages"] = mcp::json::array();
|
||||
request["max_tokens"] = llm_max_tokens_;
|
||||
|
||||
// 添加消息
|
||||
for (const auto& message : messages) {
|
||||
mcp::json msg_json;
|
||||
|
||||
// 设置角色
|
||||
switch (message.role) {
|
||||
case MessageRole::SYSTEM:
|
||||
msg_json["role"] = "system";
|
||||
break;
|
||||
case MessageRole::USER:
|
||||
msg_json["role"] = "user";
|
||||
break;
|
||||
case MessageRole::ASSISTANT:
|
||||
msg_json["role"] = "assistant";
|
||||
break;
|
||||
case MessageRole::TOOL:
|
||||
// 工具消息现在被转换为用户消息,所以这里不应该有工具消息
|
||||
std::cerr << "警告:发现工具消息,但我们现在将工具消息转换为用户消息" << std::endl;
|
||||
continue; // 跳过这个消息
|
||||
}
|
||||
|
||||
msg_json["content"] = message.content;
|
||||
request["messages"].push_back(msg_json);
|
||||
}
|
||||
|
||||
// 添加工具定义
|
||||
if (available_tools_ && available_tools_->size() > 0) {
|
||||
request["tools"] = mcp::json::array();
|
||||
|
||||
for (const auto& tool_name : available_tools_->getToolNames()) {
|
||||
ToolBase* tool = available_tools_->getTool(tool_name);
|
||||
if (tool) {
|
||||
// 构建工具JSON
|
||||
mcp::json tool_json;
|
||||
tool_json["type"] = "function";
|
||||
tool_json["function"]["name"] = tool->getName();
|
||||
tool_json["function"]["description"] = tool->getDescription();
|
||||
tool_json["function"]["parameters"] = tool->getParameters();
|
||||
|
||||
request["tools"].push_back(tool_json);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置工具选择策略
|
||||
request["tool_choice"] = "auto";
|
||||
}
|
||||
} else {
|
||||
// 默认OpenAI兼容格式
|
||||
request["model"] = llm_model_;
|
||||
request["messages"] = mcp::json::array();
|
||||
|
||||
// 添加消息
|
||||
for (const auto& message : messages) {
|
||||
mcp::json msg_json;
|
||||
|
||||
// 设置角色
|
||||
switch (message.role) {
|
||||
case MessageRole::SYSTEM:
|
||||
msg_json["role"] = "system";
|
||||
break;
|
||||
case MessageRole::USER:
|
||||
msg_json["role"] = "user";
|
||||
break;
|
||||
case MessageRole::ASSISTANT:
|
||||
msg_json["role"] = "assistant";
|
||||
break;
|
||||
case MessageRole::TOOL:
|
||||
// 工具消息现在被转换为用户消息,所以这里不应该有工具消息
|
||||
std::cerr << "警告:发现工具消息,但我们现在将工具消息转换为用户消息" << std::endl;
|
||||
msg_json["role"] = "user";
|
||||
break;
|
||||
}
|
||||
|
||||
msg_json["content"] = message.content;
|
||||
request["messages"].push_back(msg_json);
|
||||
}
|
||||
|
||||
// 添加工具定义
|
||||
if (available_tools_ && available_tools_->size() > 0) {
|
||||
request["tools"] = mcp::json::array();
|
||||
|
||||
for (const auto& tool_name : available_tools_->getToolNames()) {
|
||||
ToolBase* tool = available_tools_->getTool(tool_name);
|
||||
if (tool) {
|
||||
// 构建工具JSON
|
||||
mcp::json tool_json;
|
||||
tool_json["type"] = "function";
|
||||
tool_json["function"]["name"] = tool->getName();
|
||||
tool_json["function"]["description"] = tool->getDescription();
|
||||
tool_json["function"]["parameters"] = tool->getParameters();
|
||||
|
||||
request["tools"].push_back(tool_json);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置工具选择策略
|
||||
request["tool_choice"] = "auto";
|
||||
}
|
||||
}
|
||||
|
||||
// freopen("request.json", "w", stdout);
|
||||
// std::cout << request.dump(2) << std::endl;
|
||||
// fclose(stdout);
|
||||
|
||||
// 发送请求
|
||||
std::string request_str = request.dump();
|
||||
httplib::Headers headers = {
|
||||
{"Content-Type", "application/json"}
|
||||
};
|
||||
|
||||
// 添加Authorization头部
|
||||
if (!llm_api_key_.empty()) {
|
||||
headers.emplace("Authorization", "Bearer " + llm_api_key_);
|
||||
}
|
||||
|
||||
auto response = http_client_->Post(llm_api_endpoint_, headers, request_str, "application/json");
|
||||
|
||||
if (response && response->status == 200) {
|
||||
// 解析响应
|
||||
mcp::json response_json = mcp::json::parse(response->body);
|
||||
return response_json;
|
||||
} else {
|
||||
std::string error_msg = "LLM API调用失败";
|
||||
if (response) {
|
||||
error_msg += ": " + std::to_string(response->status) + " " + response->body;
|
||||
}
|
||||
throw std::runtime_error(error_msg);
|
||||
}
|
||||
}
|
||||
|
||||
std::string ToolCallAgent::act() {
|
||||
std::string result;
|
||||
|
||||
// 如果有工具调用,增加计数器
|
||||
if (!tool_calls_.empty()) {
|
||||
consecutive_tool_calls_++;
|
||||
std::cout << "🔄 连续工具调用次数: " << consecutive_tool_calls_ << "/" << max_consecutive_tool_calls_ << std::endl;
|
||||
} else {
|
||||
// 如果没有工具调用,重置计数器
|
||||
consecutive_tool_calls_ = 0;
|
||||
}
|
||||
|
||||
// 执行所有工具调用
|
||||
for (auto& tool_call : tool_calls_) {
|
||||
std::string tool_result = executeToolCall(tool_call);
|
||||
tool_call.setResult(tool_result);
|
||||
|
||||
// 处理特殊工具
|
||||
if (isSpecialTool(tool_call.getName())) {
|
||||
handleSpecialTool(tool_call.getName(), tool_result);
|
||||
}
|
||||
|
||||
// 将工具结果添加为用户消息,使用明确的格式
|
||||
std::string tool_message = "工具执行结果 [" + tool_call.getName() + "]: \n```json\n" + tool_result + "\n```\n请根据这个结果继续你的任务。";
|
||||
// std::cout << "📝 添加消息到历史: " << tool_message << std::endl;
|
||||
addMessage(Message::userMessage(tool_message));
|
||||
|
||||
result += tool_result + "\n";
|
||||
}
|
||||
|
||||
// 打印当前消息历史长度
|
||||
std::cout << "📚 当前消息历史长度: " << messages_.size() << std::endl;
|
||||
|
||||
// 清空工具调用列表,准备下一轮
|
||||
tool_calls_.clear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string ToolCallAgent::executeToolCall(const ToolCall& tool_call) {
|
||||
std::string name = tool_call.getName();
|
||||
mcp::json params = tool_call.getParams();
|
||||
|
||||
std::cout << "🔧 执行工具: " << name << " 参数: " << params.dump(2) << std::endl;
|
||||
|
||||
// 获取工具
|
||||
ToolBase* tool = available_tools_->getTool(name);
|
||||
if (!tool) {
|
||||
std::string error_msg = "错误:找不到工具 " + name;
|
||||
std::cout << "❌ " << error_msg << std::endl;
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
try {
|
||||
// 执行工具
|
||||
mcp::json result = tool->execute(params);
|
||||
|
||||
// 格式化结果,确保它是一个有效的JSON字符串
|
||||
std::string result_str;
|
||||
try {
|
||||
// 如果结果已经是一个JSON对象,则直接格式化
|
||||
result_str = result.dump(2);
|
||||
} catch (...) {
|
||||
// 如果结果不是一个有效的JSON对象,则将其包装为一个JSON对象
|
||||
mcp::json wrapper;
|
||||
wrapper["result"] = result.dump();
|
||||
result_str = wrapper.dump(2);
|
||||
}
|
||||
|
||||
std::cout << "✅ 工具执行结果: " << result_str << std::endl;
|
||||
return result_str;
|
||||
} catch (const std::exception& e) {
|
||||
std::string error_msg = "错误:执行工具 " + name + " 失败:" + e.what();
|
||||
std::cout << "❌ " << error_msg << std::endl;
|
||||
return error_msg;
|
||||
}
|
||||
}
|
||||
|
||||
bool ToolCallAgent::handleSpecialTool(const std::string& name, const std::string& result) {
|
||||
// 处理特殊工具,如终止工具
|
||||
if (name == "Terminate") {
|
||||
std::cout << "🛑 收到终止指令,停止执行" << std::endl;
|
||||
// 添加一条消息,表示任务已完成
|
||||
addMessage(Message::assistantMessage("任务已完成,执行已终止。"));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ToolCallAgent::shouldFinishExecution() {
|
||||
// 检查是否应该结束执行
|
||||
|
||||
// 检查是否达到最大步骤数
|
||||
if (current_step_ >= max_steps_) {
|
||||
std::cout << "⚠️ 达到最大步骤数限制(" << max_steps_ << "),停止执行" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果连续工具调用次数超过限制,也应该结束执行
|
||||
if (consecutive_tool_calls_ >= max_consecutive_tool_calls_) {
|
||||
std::cout << "⚠️ 达到最大连续工具调用次数限制(" << max_consecutive_tool_calls_ << "),停止执行" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ToolCallAgent::isSpecialTool(const std::string& name) {
|
||||
// 检查是否是特殊工具
|
||||
// 目前只有Terminate是特殊工具
|
||||
if (name == "Terminate") {
|
||||
std::cout << "🔍 识别到特殊工具: Terminate" << std::endl;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace openmanus
|
|
@ -0,0 +1,35 @@
|
|||
#include "include/tool_collection.h"
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
ToolCollection::ToolCollection() {
|
||||
// 初始化工具集合
|
||||
}
|
||||
|
||||
void ToolCollection::addTool(std::unique_ptr<ToolBase> tool) {
|
||||
if (tool) {
|
||||
std::string name = tool->getName();
|
||||
tools_[name] = std::move(tool);
|
||||
}
|
||||
}
|
||||
|
||||
ToolBase* ToolCollection::getTool(const std::string& name) {
|
||||
auto it = tools_.find(name);
|
||||
if (it != tools_.end()) {
|
||||
return it->second.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<std::string> ToolCollection::getToolNames() const {
|
||||
std::vector<std::string> names;
|
||||
names.reserve(tools_.size());
|
||||
|
||||
for (const auto& pair : tools_) {
|
||||
names.push_back(pair.first);
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
} // namespace openmanus
|
|
@ -0,0 +1,242 @@
|
|||
#include "include/tools/planning.h"
|
||||
#include "mcp/include/mcp_tool.h"
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
Planning::Planning()
|
||||
: ToolBase("planning", "创建和管理结构化计划") {
|
||||
// 使用tool_builder构建工具定义
|
||||
mcp::tool_builder builder("planning");
|
||||
builder.with_description("创建和管理结构化计划");
|
||||
|
||||
// 添加参数
|
||||
builder.with_string_param("action", "要执行的操作", true);
|
||||
builder.with_string_param("plan_id", "计划ID", false);
|
||||
builder.with_string_param("title", "计划标题", false);
|
||||
builder.with_string_param("description", "计划描述", false);
|
||||
builder.with_array_param("steps", "计划步骤列表", "string", false);
|
||||
builder.with_string_param("step_id", "步骤ID", false);
|
||||
builder.with_string_param("step_description", "步骤描述", false);
|
||||
builder.with_string_param("status", "步骤状态", false);
|
||||
|
||||
mcp::tool tool = builder.build();
|
||||
|
||||
// 从构建的工具中获取参数定义
|
||||
parameters_ = tool.parameters_schema;
|
||||
|
||||
// 手动添加enum约束
|
||||
if (parameters_.contains("properties") && parameters_["properties"].contains("action")) {
|
||||
parameters_["properties"]["action"]["enum"] = {"create_plan", "get_plan_status", "update_step_status", "add_step"};
|
||||
}
|
||||
|
||||
// 手动添加status的enum约束
|
||||
if (parameters_.contains("properties") && parameters_["properties"].contains("status")) {
|
||||
parameters_["properties"]["status"]["enum"] = {"pending", "in_progress", "completed", "failed"};
|
||||
}
|
||||
}
|
||||
|
||||
mcp::json Planning::execute(const mcp::json& params) {
|
||||
if (!params.contains("action")) {
|
||||
return {
|
||||
{"success", false},
|
||||
{"error", "缺少action参数"}
|
||||
};
|
||||
}
|
||||
|
||||
std::string action = params["action"];
|
||||
|
||||
if (action == "create_plan") {
|
||||
return createPlan(params);
|
||||
} else if (action == "get_plan_status") {
|
||||
return getPlanStatus(params);
|
||||
} else if (action == "update_step_status") {
|
||||
return updateStepStatus(params);
|
||||
} else if (action == "add_step") {
|
||||
return addStep(params);
|
||||
} else {
|
||||
return {
|
||||
{"success", false},
|
||||
{"error", "未知的action: " + action}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
mcp::json Planning::createPlan(const mcp::json& params) {
|
||||
if (!params.contains("title") || !params.contains("description")) {
|
||||
return {
|
||||
{"success", false},
|
||||
{"error", "缺少title或description参数"}
|
||||
};
|
||||
}
|
||||
|
||||
// 生成计划ID
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto now_time_t = std::chrono::system_clock::to_time_t(now);
|
||||
std::stringstream ss;
|
||||
ss << "plan_" << std::put_time(std::localtime(&now_time_t), "%Y%m%d%H%M%S");
|
||||
std::string plan_id = ss.str();
|
||||
|
||||
// 创建计划
|
||||
Plan plan;
|
||||
plan.id = plan_id;
|
||||
plan.title = params["title"];
|
||||
plan.description = params["description"];
|
||||
plan.current_step_index = 0;
|
||||
|
||||
// 添加步骤
|
||||
if (params.contains("steps") && params["steps"].is_array()) {
|
||||
for (size_t i = 0; i < params["steps"].size(); ++i) {
|
||||
std::string step_id = "step_" + std::to_string(i + 1);
|
||||
std::string step_description = params["steps"][i];
|
||||
|
||||
plan.step_ids.push_back(step_id);
|
||||
plan.step_descriptions[step_id] = step_description;
|
||||
plan.step_statuses[step_id] = "pending";
|
||||
}
|
||||
}
|
||||
|
||||
// 保存计划
|
||||
plans_[plan_id] = plan;
|
||||
|
||||
return {
|
||||
{"success", true},
|
||||
{"plan_id", plan_id},
|
||||
{"message", "计划创建成功"}
|
||||
};
|
||||
}
|
||||
|
||||
mcp::json Planning::getPlanStatus(const mcp::json& params) {
|
||||
if (!params.contains("plan_id")) {
|
||||
return {
|
||||
{"success", false},
|
||||
{"error", "缺少plan_id参数"}
|
||||
};
|
||||
}
|
||||
|
||||
std::string plan_id = params["plan_id"];
|
||||
|
||||
// 查找计划
|
||||
auto it = plans_.find(plan_id);
|
||||
if (it == plans_.end()) {
|
||||
return {
|
||||
{"success", false},
|
||||
{"error", "找不到计划: " + plan_id}
|
||||
};
|
||||
}
|
||||
|
||||
const Plan& plan = it->second;
|
||||
|
||||
// 构建步骤信息
|
||||
mcp::json steps = mcp::json::array();
|
||||
for (const auto& step_id : plan.step_ids) {
|
||||
steps.push_back({
|
||||
{"id", step_id},
|
||||
{"description", plan.step_descriptions.at(step_id)},
|
||||
{"status", plan.step_statuses.at(step_id)}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
{"success", true},
|
||||
{"plan", {
|
||||
{"id", plan.id},
|
||||
{"title", plan.title},
|
||||
{"description", plan.description},
|
||||
{"steps", steps},
|
||||
{"current_step_index", plan.current_step_index}
|
||||
}}
|
||||
};
|
||||
}
|
||||
|
||||
mcp::json Planning::updateStepStatus(const mcp::json& params) {
|
||||
if (!params.contains("plan_id") || !params.contains("step_id") || !params.contains("status")) {
|
||||
return {
|
||||
{"success", false},
|
||||
{"error", "缺少plan_id、step_id或status参数"}
|
||||
};
|
||||
}
|
||||
|
||||
std::string plan_id = params["plan_id"];
|
||||
std::string step_id = params["step_id"];
|
||||
std::string status = params["status"];
|
||||
|
||||
// 查找计划
|
||||
auto it = plans_.find(plan_id);
|
||||
if (it == plans_.end()) {
|
||||
return {
|
||||
{"success", false},
|
||||
{"error", "找不到计划: " + plan_id}
|
||||
};
|
||||
}
|
||||
|
||||
Plan& plan = it->second;
|
||||
|
||||
// 查找步骤
|
||||
auto step_status_it = plan.step_statuses.find(step_id);
|
||||
if (step_status_it == plan.step_statuses.end()) {
|
||||
return {
|
||||
{"success", false},
|
||||
{"error", "找不到步骤: " + step_id}
|
||||
};
|
||||
}
|
||||
|
||||
// 更新步骤状态
|
||||
step_status_it->second = status;
|
||||
|
||||
// 如果步骤完成,更新当前步骤索引
|
||||
if (status == "completed") {
|
||||
for (size_t i = 0; i < plan.step_ids.size(); ++i) {
|
||||
if (plan.step_ids[i] == step_id && i == plan.current_step_index) {
|
||||
plan.current_step_index = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
{"success", true},
|
||||
{"message", "步骤状态更新成功"}
|
||||
};
|
||||
}
|
||||
|
||||
mcp::json Planning::addStep(const mcp::json& params) {
|
||||
if (!params.contains("plan_id") || !params.contains("step_description")) {
|
||||
return {
|
||||
{"success", false},
|
||||
{"error", "缺少plan_id或step_description参数"}
|
||||
};
|
||||
}
|
||||
|
||||
std::string plan_id = params["plan_id"];
|
||||
std::string step_description = params["step_description"];
|
||||
|
||||
// 查找计划
|
||||
auto it = plans_.find(plan_id);
|
||||
if (it == plans_.end()) {
|
||||
return {
|
||||
{"success", false},
|
||||
{"error", "找不到计划: " + plan_id}
|
||||
};
|
||||
}
|
||||
|
||||
Plan& plan = it->second;
|
||||
|
||||
// 生成步骤ID
|
||||
std::string step_id = "step_" + std::to_string(plan.step_ids.size() + 1);
|
||||
|
||||
// 添加步骤
|
||||
plan.step_ids.push_back(step_id);
|
||||
plan.step_descriptions[step_id] = step_description;
|
||||
plan.step_statuses[step_id] = "pending";
|
||||
|
||||
return {
|
||||
{"success", true},
|
||||
{"step_id", step_id},
|
||||
{"message", "步骤添加成功"}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace openmanus
|
|
@ -0,0 +1,48 @@
|
|||
#include "include/tools/python_execute.h"
|
||||
#include "mcp/include/mcp_client.h"
|
||||
#include "mcp/include/mcp_tool.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
PythonExecute::PythonExecute()
|
||||
: ToolBase("PythonExecute", "执行Python代码并返回结果") {
|
||||
// 使用tool_builder构建工具定义
|
||||
mcp::tool_builder builder("PythonExecute");
|
||||
builder.with_description("执行Python代码并返回结果");
|
||||
builder.with_string_param("code", "要执行的Python代码", true);
|
||||
mcp::tool tool = builder.build();
|
||||
|
||||
// 从构建的工具中获取参数定义
|
||||
parameters_ = tool.parameters_schema;
|
||||
}
|
||||
|
||||
mcp::json PythonExecute::execute(const mcp::json& params) {
|
||||
if (!params.contains("code")) {
|
||||
throw std::runtime_error("缺少'code'参数");
|
||||
}
|
||||
|
||||
std::string code = params["code"];
|
||||
|
||||
try {
|
||||
// 创建MCP客户端
|
||||
mcp::client client("localhost", 8080);
|
||||
|
||||
// 初始化客户端
|
||||
client.initialize("OpenManusCppClient", "0.1.0");
|
||||
|
||||
// 调用PythonExecute工具
|
||||
mcp::json tool_params = {{"code", code}};
|
||||
mcp::json result = client.call_tool("PythonExecute", tool_params);
|
||||
|
||||
return result;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "执行Python代码失败: " << e.what() << std::endl;
|
||||
mcp::json error_result;
|
||||
error_result["success"] = false;
|
||||
error_result["error"] = e.what();
|
||||
return error_result;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace openmanus
|
|
@ -0,0 +1,25 @@
|
|||
#include "include/tools/terminate.h"
|
||||
#include "mcp/include/mcp_tool.h"
|
||||
|
||||
namespace openmanus {
|
||||
|
||||
Terminate::Terminate()
|
||||
: ToolBase("Terminate", "当任务完成时调用此工具来结束执行。任务完成后必须调用此工具。") {
|
||||
// 使用tool_builder构建工具定义
|
||||
mcp::tool_builder builder("Terminate");
|
||||
builder.with_description("当任务完成时调用此工具来结束执行。任务完成后必须调用此工具。");
|
||||
mcp::tool tool = builder.build();
|
||||
|
||||
// 从构建的工具中获取参数定义
|
||||
parameters_ = tool.parameters_schema;
|
||||
}
|
||||
|
||||
mcp::json Terminate::execute(const mcp::json& params) {
|
||||
// 终止工具不需要任何参数,也不需要执行任何操作
|
||||
// 它的存在只是为了通知代理终止执行
|
||||
mcp::json result;
|
||||
result["message"] = "执行已终止";
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace openmanus
|
Loading…
Reference in New Issue