#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>
#include <cxxopts.hpp>
#include "agent.hpp"
#include "calculator_tool.hpp"
#include "llm_client.hpp"
#include "memory.hpp"
// A simple coroutine runner since our Task is mostly synchronous right now
void runTask(Task<mw::E<std::string>> task)
{
auto res = task.get();
if(res.has_value())
{
std::cout << "Agent: " << res.value() << "\n";
}
else
{
std::cout << "Agent Error: " << mw::errorMsg(res.error()) << "\n";
}
}
int main(int argc, char** argv)
{
cxxopts::Options options("agent_smith", "C++ LLM Agent Framework");
options.add_options()
("k,api-key", "LLM API Key", cxxopts::value<std::string>())
("e,endpoint", "LLM API Endpoint (Base URL)",
cxxopts::value<std::string>()->default_value(
"https://api.openai.com/v1"))
("m,model", "LLM Model Name",
cxxopts::value<std::string>()->default_value("gpt-4o"))
("h,help", "Print usage")
;
auto result = options.parse(argc, argv);
if(result.count("help"))
{
std::cout << options.help() << "\n";
return 0;
}
std::string api_key;
if(result.count("api-key"))
{
api_key = result["api-key"].as<std::string>();
}
else if(const char* env_key = std::getenv("OPENAI_API_KEY"))
{
api_key = env_key;
}
else
{
std::cerr << "Error: API key must be provided via --api-key or "
<< "OPENAI_API_KEY environment variable.\n";
return 1;
}
std::string endpoint = result["endpoint"].as<std::string>();
std::string model = result["model"].as<std::string>();
auto client = std::make_unique<OpenAiClient>(api_key, model, endpoint);
auto memory = std::make_unique<InMemoryMemory>();
ToolRegistry tool_registry;
auto reg_res =
tool_registry.registerTool(std::make_unique<CalculatorTool>());
if(!reg_res.has_value())
{
std::cerr << "Failed to register tool: "
<< mw::errorMsg(reg_res.error()) << "\n";
return 1;
}
Agent agent(std::move(client), std::move(memory), tool_registry);
auto allow_res = agent.allowTool("calculator");
if(!allow_res.has_value())
{
std::cerr << "Failed to allow tool: " << mw::errorMsg(allow_res.error())
<< "\n";
return 1;
}
Skill default_skill{
"calculator_assistant",
"You are a helpful assistant that can perform calculations. "
"Use the calculator tool when needed.",
{"calculator"}};
agent.activateSkill(default_skill);
std::cout << "Agent Smith initialized.\n"
<< "Endpoint: " << endpoint << "\n"
<< "Model: " << model << "\n"
<< "Type 'exit' to quit.\n";
std::string user_input;
while(true)
{
std::cout << "You: ";
if(!std::getline(std::cin, user_input) || user_input == "exit")
{
break;
}
try
{
runTask(agent.run(user_input));
}
catch(const std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
}
return 0;
}