remove unused codes; refactor project structure
parent
4c7a790811
commit
eb77c83236
|
@ -61,6 +61,8 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/server)
|
||||||
|
|
||||||
# include
|
# include
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/common)
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/mcp/include)
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/mcp/include)
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/mcp/common)
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/mcp/common)
|
||||||
|
|
||||||
|
@ -90,13 +92,13 @@ file(GLOB MEMORY_SOURCES
|
||||||
"memory/*/*/*.cc"
|
"memory/*/*/*.cc"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 创建humanus核心库,包含所有共享组件
|
# humanus core
|
||||||
add_library(humanus
|
add_library(humanus
|
||||||
config.cpp
|
src/config.cpp
|
||||||
llm.cpp
|
src/llm.cpp
|
||||||
prompt.cpp
|
src/prompt.cpp
|
||||||
logger.cpp
|
src/logger.cpp
|
||||||
schema.cpp
|
src/schema.cpp
|
||||||
${AGENT_SOURCES}
|
${AGENT_SOURCES}
|
||||||
${TOOL_SOURCES}
|
${TOOL_SOURCES}
|
||||||
${FLOW_SOURCES}
|
${FLOW_SOURCES}
|
||||||
|
@ -104,9 +106,10 @@ add_library(humanus
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(humanus PUBLIC Threads::Threads mcp ${OPENSSL_LIBRARIES})
|
target_link_libraries(humanus PUBLIC Threads::Threads mcp ${OPENSSL_LIBRARIES})
|
||||||
|
|
||||||
if(Python3_FOUND)
|
if(Python3_FOUND)
|
||||||
target_link_libraries(humanus PUBLIC ${Python3_LIBRARIES})
|
target_link_libraries(humanus PUBLIC ${Python3_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# 添加examples目录
|
# examples
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/examples)
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/examples)
|
|
@ -9,7 +9,6 @@
|
||||||
#include "tool/terminate.h"
|
#include "tool/terminate.h"
|
||||||
#include "tool/puppeteer.h"
|
#include "tool/puppeteer.h"
|
||||||
#include "tool/filesystem.h"
|
#include "tool/filesystem.h"
|
||||||
#include "tool/shell.h"
|
|
||||||
|
|
||||||
namespace humanus {
|
namespace humanus {
|
||||||
|
|
||||||
|
|
|
@ -1,248 +0,0 @@
|
||||||
#include "planning.h"
|
|
||||||
#include <iomanip>
|
|
||||||
|
|
||||||
namespace humanus {
|
|
||||||
|
|
||||||
// Initialize the agent with a default plan ID and validate required tools.
|
|
||||||
void PlanningAgent::initialize_plan_and_verify_tools() {
|
|
||||||
active_plan_id = "plan_" + std::to_string(std::chrono::system_clock::now().time_since_epoch().count());
|
|
||||||
|
|
||||||
if (available_tools.tools_map.find("planning") == available_tools.tools_map.end()) {
|
|
||||||
available_tools.add_tool(std::make_shared<PlanningTool>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decide the next action based on plan status.
|
|
||||||
bool PlanningAgent::think() {
|
|
||||||
std::string prompt;
|
|
||||||
if (!active_plan_id.empty()) {
|
|
||||||
prompt = "CURRENT PLAN STATUS:\n" + get_plan();
|
|
||||||
}
|
|
||||||
memory->add_message(Message::user_message(prompt));
|
|
||||||
|
|
||||||
// Get the current step index before thinking
|
|
||||||
current_step_index = _get_current_step_index();
|
|
||||||
|
|
||||||
bool result = ToolCallAgent::think(); // Will set tool_calls
|
|
||||||
|
|
||||||
// After thinking, if we decided to execute a tool and it's not a planning tool or special tool,
|
|
||||||
// associate it with the current step for tracking
|
|
||||||
if (result && !tool_calls.empty()) {
|
|
||||||
auto latest_tool_call = tool_calls.back(); // Get the most recent tool call
|
|
||||||
if (latest_tool_call.function.name != "planning"
|
|
||||||
&& !_is_special_tool(latest_tool_call.function.name)
|
|
||||||
&& current_step_index >= 0) {
|
|
||||||
step_execution_tracker[latest_tool_call.id] = {
|
|
||||||
{"step_index", current_step_index},
|
|
||||||
{"tool_name", latest_tool_call.function.name},
|
|
||||||
{"step_status", "pending"} // Will be updated after execution
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute a step and track its completion status.
|
|
||||||
std::string PlanningAgent::act() {
|
|
||||||
std::string result = ToolCallAgent::act();
|
|
||||||
|
|
||||||
// After executing the tool, update the plan status
|
|
||||||
if (!tool_calls.empty()) {
|
|
||||||
auto latest_tool_call = tool_calls.back();
|
|
||||||
|
|
||||||
// Update the execution status to completed
|
|
||||||
if (step_execution_tracker.find(latest_tool_call.id) != step_execution_tracker.end()) {
|
|
||||||
step_execution_tracker[latest_tool_call.id]["status"] = "completed";
|
|
||||||
step_execution_tracker[latest_tool_call.id]["result"] = result;
|
|
||||||
|
|
||||||
// Update the plan status if this was a non-planning, non-special tool
|
|
||||||
if (
|
|
||||||
latest_tool_call.function.name != "planning"
|
|
||||||
&& !_is_special_tool(latest_tool_call.function.name)
|
|
||||||
) {
|
|
||||||
update_plan_status(latest_tool_call.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the current plan status.
|
|
||||||
std::string PlanningAgent::get_plan() {
|
|
||||||
if (active_plan_id.empty()) {
|
|
||||||
return "No active plan. Please create a plan first.";
|
|
||||||
}
|
|
||||||
|
|
||||||
ToolResult result = available_tools.execute(
|
|
||||||
"planning",
|
|
||||||
{{"command", "get"}, {"plan_id", active_plan_id}}
|
|
||||||
);
|
|
||||||
|
|
||||||
return result.to_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the agent with an optional initial request.
|
|
||||||
std::string PlanningAgent::run(const std::string& request) {
|
|
||||||
if (!request.empty()) {
|
|
||||||
create_initial_plan(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
return BaseAgent::run();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the current plan progress based on completed tool execution.
|
|
||||||
// Only marks a step as completed if the associated tool has been successfully executed.
|
|
||||||
void PlanningAgent::update_plan_status(const std::string& tool_call_id) {
|
|
||||||
if (active_plan_id.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (step_execution_tracker.find(tool_call_id) == step_execution_tracker.end()) {
|
|
||||||
logger->warn("No step tracking found for tool call " + tool_call_id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tracker = step_execution_tracker[tool_call_id];
|
|
||||||
if (tracker["status"] != "completed") {
|
|
||||||
logger->warn("Tool call " + tool_call_id + " has not completed successfully");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int step_index = tracker["step_index"];
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Mark the step as completed
|
|
||||||
ToolResult result = available_tools.execute(
|
|
||||||
"planning",
|
|
||||||
{
|
|
||||||
{"command", "mark_step"},
|
|
||||||
{"plan_id", active_plan_id},
|
|
||||||
{"step_index", step_index},
|
|
||||||
{"step_status", "completed"}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
logger->info(
|
|
||||||
"Marked step " + std::to_string(step_index) + " as completed in plan " + active_plan_id
|
|
||||||
+ "\n\n" + result.to_string() + "\n\n"
|
|
||||||
);
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
logger->warn("Failed to update plan status: " + std::string(e.what()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the current plan to identify the first non-completed step's index.
|
|
||||||
// Returns -1 if no active step is found.
|
|
||||||
int PlanningAgent::_get_current_step_index() {
|
|
||||||
if (active_plan_id.empty()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto plan = get_plan();
|
|
||||||
|
|
||||||
auto splitlines = [](const std::string& s) {
|
|
||||||
std::vector<std::string> lines;
|
|
||||||
std::istringstream iss(s);
|
|
||||||
std::string line;
|
|
||||||
while (std::getline(iss, line)) {
|
|
||||||
lines.push_back(line);
|
|
||||||
}
|
|
||||||
return lines;
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
std::vector<std::string> plan_lines = splitlines(plan);
|
|
||||||
int steps_index = -1;
|
|
||||||
|
|
||||||
// Find the index of the "Steps:" line
|
|
||||||
for (size_t i = 0; i < plan_lines.size(); ++i) {
|
|
||||||
if (plan_lines[i].find("Steps:") == 0) {
|
|
||||||
steps_index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (steps_index == -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the first non-completed step
|
|
||||||
for (size_t i = steps_index + 1; i < plan_lines.size(); ++i) {
|
|
||||||
std::string line = plan_lines[i];
|
|
||||||
if (line.find("[ ]") != std::string::npos || line.find("[→]") != std::string::npos) { // not_started or in_progress
|
|
||||||
// Mark current step as in_progress
|
|
||||||
available_tools.execute(
|
|
||||||
"planning",
|
|
||||||
{
|
|
||||||
{"command", "mark_step"},
|
|
||||||
{"plan_id", active_plan_id},
|
|
||||||
{"step_index", i},
|
|
||||||
{"step_status", "in_progress"}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1; // # No active step found
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
logger->warn("Error finding current step index: " + std::string(e.what()));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create an initial plan based on the request.
|
|
||||||
void PlanningAgent::create_initial_plan(const std::string& request) {
|
|
||||||
logger->info("Creating initial plan with ID: " + active_plan_id);
|
|
||||||
|
|
||||||
std::vector<Message> messages = {
|
|
||||||
Message::user_message(
|
|
||||||
"Analyze the request and create a plan with ID " + active_plan_id + ": " + request
|
|
||||||
)
|
|
||||||
};
|
|
||||||
memory->add_messages(messages);
|
|
||||||
json response = llm->ask_tool(
|
|
||||||
messages,
|
|
||||||
system_prompt,
|
|
||||||
next_step_prompt,
|
|
||||||
available_tools.to_params(),
|
|
||||||
tool_choice
|
|
||||||
);
|
|
||||||
|
|
||||||
tool_calls = ToolCall::from_json_list(response["tool_calls"]);
|
|
||||||
|
|
||||||
Message assistant_msg = Message::assistant_message(
|
|
||||||
response["content"], tool_calls
|
|
||||||
);
|
|
||||||
|
|
||||||
memory->add_message(assistant_msg);
|
|
||||||
|
|
||||||
bool plan_created = false;
|
|
||||||
for (const ToolCall& tool_call : tool_calls) {
|
|
||||||
if (tool_call.function.name == "planning") {
|
|
||||||
std::string result = execute_tool(tool_call);
|
|
||||||
logger->info("Executed tool " + tool_call.function.name + " with result: " + result);
|
|
||||||
|
|
||||||
// Add tool response to memory
|
|
||||||
Message tool_msg = Message::tool_message(
|
|
||||||
result,
|
|
||||||
tool_call.id,
|
|
||||||
tool_call.function.name
|
|
||||||
);
|
|
||||||
memory->add_message(tool_msg);
|
|
||||||
plan_created = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!plan_created) {
|
|
||||||
logger->warn("No plan created from initial request");
|
|
||||||
Message tool_msg = Message::assistant_message(
|
|
||||||
"Error: Parameter `plan_id` is required for command: create"
|
|
||||||
);
|
|
||||||
memory->add_message(tool_msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace humanus
|
|
|
@ -1,91 +0,0 @@
|
||||||
#ifndef HUMANUS_AGENT_PLANNING_H
|
|
||||||
#define HUMANUS_AGENT_PLANNING_H
|
|
||||||
|
|
||||||
#include "toolcall.h"
|
|
||||||
#include "tool/planning.h"
|
|
||||||
#include "prompt.h"
|
|
||||||
|
|
||||||
namespace humanus {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An agent that creates and manages plans to solve tasks.
|
|
||||||
|
|
||||||
* This agent uses a planning tool to create and manage structured plans,
|
|
||||||
* and tracks progress through individual steps until task completion.
|
|
||||||
*/
|
|
||||||
struct PlanningAgent : ToolCallAgent {
|
|
||||||
std::string active_plan_id;
|
|
||||||
|
|
||||||
// Add a dictionary to track the step status for each tool call
|
|
||||||
std::map<std::string, json> step_execution_tracker;
|
|
||||||
int current_step_index;
|
|
||||||
|
|
||||||
PlanningAgent(
|
|
||||||
const ToolCollection& available_tools = ToolCollection(
|
|
||||||
{
|
|
||||||
std::make_shared<PlanningTool>(),
|
|
||||||
std::make_shared<Terminate>()
|
|
||||||
}
|
|
||||||
),
|
|
||||||
const std::string& tool_choice = "auto",
|
|
||||||
const std::set<std::string>& special_tool_names = {"terminate"},
|
|
||||||
const std::string& name = "planning",
|
|
||||||
const std::string& description = "An agent that creates and manages plans to solve tasks",
|
|
||||||
const std::string& system_prompt = prompt::planning::PLANNING_SYSTEM_PROMPT,
|
|
||||||
const std::string& next_step_prompt = prompt::planning::NEXT_STEP_PROMPT,
|
|
||||||
const std::shared_ptr<LLM>& llm = nullptr,
|
|
||||||
const std::shared_ptr<BaseMemory>& memory = nullptr,
|
|
||||||
AgentState state = AgentState::IDLE,
|
|
||||||
int max_steps = 20,
|
|
||||||
int current_step = 0,
|
|
||||||
int duplicate_threshold = 2
|
|
||||||
) : ToolCallAgent(
|
|
||||||
available_tools,
|
|
||||||
tool_choice,
|
|
||||||
special_tool_names,
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
system_prompt,
|
|
||||||
next_step_prompt,
|
|
||||||
llm,
|
|
||||||
memory,
|
|
||||||
state,
|
|
||||||
max_steps,
|
|
||||||
current_step,
|
|
||||||
duplicate_threshold
|
|
||||||
) {
|
|
||||||
current_step_index = -1; // will be set in think()
|
|
||||||
initialize_plan_and_verify_tools();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the agent with a default plan ID and validate required tools.
|
|
||||||
void initialize_plan_and_verify_tools();
|
|
||||||
|
|
||||||
// Decide the next action based on plan status.
|
|
||||||
bool think() override;
|
|
||||||
|
|
||||||
// Execute a step and track its completion status.
|
|
||||||
std::string act() override;
|
|
||||||
|
|
||||||
// Retrieve the current plan status.
|
|
||||||
std::string get_plan();
|
|
||||||
|
|
||||||
// Run the agent with an optional initial request.
|
|
||||||
std::string run(const std::string& request = "") override;
|
|
||||||
|
|
||||||
// Update the current plan progress based on completed tool execution.
|
|
||||||
// Only marks a step as completed if the associated tool has been successfully executed.
|
|
||||||
void update_plan_status(const std::string& tool_call_id);
|
|
||||||
|
|
||||||
// Parse the current plan to identify the first non-completed step's index.
|
|
||||||
// Returns None if no active step is found.
|
|
||||||
int _get_current_step_index();
|
|
||||||
|
|
||||||
// Create an initial plan based on the request.
|
|
||||||
void create_initial_plan(const std::string& request);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace humanus
|
|
||||||
|
|
||||||
#endif // HUMANUS_AGENT_PLANNING_H
|
|
69
agent/swe.h
69
agent/swe.h
|
@ -1,69 +0,0 @@
|
||||||
#ifndef HUMANUS_AGENT_SWE_H
|
|
||||||
#define HUMANUS_AGENT_SWE_H
|
|
||||||
|
|
||||||
#include "toolcall.h"
|
|
||||||
#include "tool/tool_collection.h"
|
|
||||||
#include "tool/terminate.h"
|
|
||||||
#include "tool/shell.h"
|
|
||||||
#include "tool/filesystem.h"
|
|
||||||
#include "prompt.h"
|
|
||||||
|
|
||||||
namespace humanus {
|
|
||||||
|
|
||||||
// An agent that implements the SWEAgent paradigm for executing code and natural conversations.
|
|
||||||
struct SweAgent : ToolCallAgent {
|
|
||||||
std::string working_dir;
|
|
||||||
|
|
||||||
SweAgent(
|
|
||||||
const std::string& working_dir = ".",
|
|
||||||
const ToolCollection& available_tools = ToolCollection(
|
|
||||||
{
|
|
||||||
std::make_shared<Shell>(),
|
|
||||||
std::make_shared<Filesystem>(),
|
|
||||||
std::make_shared<Terminate>()
|
|
||||||
}
|
|
||||||
),
|
|
||||||
const std::string& tool_choice = "auto",
|
|
||||||
const std::set<std::string>& special_tool_names = {"terminate"},
|
|
||||||
const std::string& name = "swe",
|
|
||||||
const std::string& description = "an autonomous AI programmer that interacts directly with the computer to solve tasks.",
|
|
||||||
const std::string& system_prompt = prompt::swe::SYSTEM_PROMPT,
|
|
||||||
const std::string& next_step_prompt = prompt::swe::NEXT_STEP_TEMPLATE,
|
|
||||||
const std::shared_ptr<LLM>& llm = nullptr,
|
|
||||||
const std::shared_ptr<BaseMemory>& memory = nullptr,
|
|
||||||
AgentState state = AgentState::IDLE,
|
|
||||||
int max_steps = 100,
|
|
||||||
int current_step = 0,
|
|
||||||
int duplicate_threshold = 2
|
|
||||||
) : ToolCallAgent(
|
|
||||||
available_tools,
|
|
||||||
tool_choice,
|
|
||||||
special_tool_names,
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
system_prompt,
|
|
||||||
next_step_prompt,
|
|
||||||
llm,
|
|
||||||
memory,
|
|
||||||
state,
|
|
||||||
max_steps,
|
|
||||||
current_step,
|
|
||||||
duplicate_threshold
|
|
||||||
),
|
|
||||||
working_dir(working_dir) {}
|
|
||||||
|
|
||||||
bool think() override {
|
|
||||||
// Update working directory
|
|
||||||
working_dir = std::filesystem::current_path().string(); // TODO: Maybe use predefined working directory?
|
|
||||||
next_step_prompt = prompt::swe::NEXT_STEP_TEMPLATE;
|
|
||||||
next_step_prompt = next_step_prompt.replace(
|
|
||||||
next_step_prompt.find("{working_dir}"), std::string("{working_dir}").length(), working_dir
|
|
||||||
);
|
|
||||||
|
|
||||||
return ToolCallAgent::think();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // HUMANUS_AGENT_SWE_H
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include "react.h"
|
#include "react.h"
|
||||||
#include "prompt.h"
|
#include "prompt.h"
|
||||||
#include "tool/tool_collection.h"
|
#include "tool/tool_collection.h"
|
||||||
#include "tool/create_chat_completion.h"
|
|
||||||
#include "tool/terminate.h"
|
#include "tool/terminate.h"
|
||||||
|
|
||||||
namespace humanus {
|
namespace humanus {
|
||||||
|
@ -19,7 +18,6 @@ struct ToolCallAgent : ReActAgent {
|
||||||
ToolCallAgent(
|
ToolCallAgent(
|
||||||
const ToolCollection& available_tools = ToolCollection(
|
const ToolCollection& available_tools = ToolCollection(
|
||||||
{
|
{
|
||||||
std::make_shared<CreateChatCompletion>(),
|
|
||||||
std::make_shared<Terminate>()
|
std::make_shared<Terminate>()
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue