BareGit
#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;
}