remove unused codes; refactor project structure
parent
4c7a790811
commit
eb77c83236
|
@ -61,6 +61,8 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/server)
|
|||
|
||||
# include
|
||||
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/common)
|
||||
|
||||
|
@ -90,13 +92,13 @@ file(GLOB MEMORY_SOURCES
|
|||
"memory/*/*/*.cc"
|
||||
)
|
||||
|
||||
# 创建humanus核心库,包含所有共享组件
|
||||
# humanus core
|
||||
add_library(humanus
|
||||
config.cpp
|
||||
llm.cpp
|
||||
prompt.cpp
|
||||
logger.cpp
|
||||
schema.cpp
|
||||
src/config.cpp
|
||||
src/llm.cpp
|
||||
src/prompt.cpp
|
||||
src/logger.cpp
|
||||
src/schema.cpp
|
||||
${AGENT_SOURCES}
|
||||
${TOOL_SOURCES}
|
||||
${FLOW_SOURCES}
|
||||
|
@ -104,9 +106,10 @@ add_library(humanus
|
|||
)
|
||||
|
||||
target_link_libraries(humanus PUBLIC Threads::Threads mcp ${OPENSSL_LIBRARIES})
|
||||
|
||||
if(Python3_FOUND)
|
||||
target_link_libraries(humanus PUBLIC ${Python3_LIBRARIES})
|
||||
endif()
|
||||
|
||||
# 添加examples目录
|
||||
# examples
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/examples)
|
|
@ -9,7 +9,6 @@
|
|||
#include "tool/terminate.h"
|
||||
#include "tool/puppeteer.h"
|
||||
#include "tool/filesystem.h"
|
||||
#include "tool/shell.h"
|
||||
|
||||
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 "prompt.h"
|
||||
#include "tool/tool_collection.h"
|
||||
#include "tool/create_chat_completion.h"
|
||||
#include "tool/terminate.h"
|
||||
|
||||
namespace humanus {
|
||||
|
@ -19,7 +18,6 @@ struct ToolCallAgent : ReActAgent {
|
|||
ToolCallAgent(
|
||||
const ToolCollection& available_tools = ToolCollection(
|
||||
{
|
||||
std::make_shared<CreateChatCompletion>(),
|
||||
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