/* Bantam: tiny, powerful, DIY AI agent — modern C++20 port * Created by Luxferre in 2026, released into the public domain. * * This is a C++20 rewrite of the pure-C port (bantam-c). It talks to any * OpenAI-compatible /chat/completions API and implements the same agentic * loop, tools, session management, markdown terminal rendering and * raw-terminal line editor. * * Design goals relative to the C port: * - Use standard, safe C++ containers (std::string, std::vector, * std::map, std::span) instead of raw memory areas. * - Eliminate hand-rolled allocation/string code; rely on RAII so there * is far less room for memory-allocation related vulnerabilities. * - Depend only on libcurl (HTTP) plus the vendored single-header * nlohmann/json library; the unsafe json-c C API is no longer used. * * Feature macros: we rely on POSIX.1-2008 interfaces. */ #ifndef BANTAM_HPP #define BANTAM_HPP #include #include #include #include #include #include #include #include /* Markdown renderer state (code-fence tracking). */ struct MdState { bool in_code = false; }; /* ------------------------------------------------------------------ */ /* Tool call / message / usage / config structures. */ /* ------------------------------------------------------------------ */ struct ToolCall { std::string id; std::string name; std::string arguments; /* raw JSON text of the arguments object */ }; struct Message { std::string role; std::string content; /* empty when absent */ std::string reasoning; /* empty when absent */ std::vector calls; std::string tool_call_id; /* empty when absent (tool role only) */ int calls_shown = 0; }; struct Messages { std::vector items; }; struct Usage { int prompt_tokens = 0; int completion_tokens = 0; int total_tokens = 0; int cached_tokens = 0; int context_tokens = 0; std::string model; }; struct Cfg { std::string endpoint; std::string model; std::string api_key; std::string color; double temperature = 0.7; int timeout = 300; int shell_timeout = 120; int max_al_iterations = 1000; int stream = 1; /* 0/1 */ int force_stream = -1; /* -1 = auto, 0/1 = force (compaction) */ int context_window = 262144; int max_tool_res = 65536; std::map raw; /* raw key/value map */ }; struct Session { std::string id; std::string created; std::string summary; Messages messages; }; /* ------------------------------------------------------------------ */ /* Globals. */ /* ------------------------------------------------------------------ */ extern int g_col; /* color enabled (0/1) */ extern volatile int g_interrupted; /* SIGINT flag */ /* ------------------------------------------------------------------ */ /* util.cpp */ /* ------------------------------------------------------------------ */ void setup_signal_handler(); int is_terminal(int fd); int to_int_val(std::string_view s, int def); std::string sfmt(const char *fmt, ...); void str_appendf(std::string &s, const char *fmt, ...); /* UTF-8 helpers. */ int utf8_decode(const unsigned char *p, size_t avail, size_t *plen); std::string_view utf8_truncate(std::string_view s, size_t max_bytes); std::string filter_text(std::string_view s); int color_enabled(const Cfg &cfg); std::string cstr(std::string_view text, std::span codes); void cprint(std::string_view text, std::span codes); int visible_len(std::string_view s); int rune_width(int cp); void mkdir_p(std::string_view dir); std::string project_id(); std::string bantam_tmp_dir(); std::string tool_res_dir(); std::string md5_hex(std::string_view data); /* ------------------------------------------------------------------ */ /* config.cpp */ /* ------------------------------------------------------------------ */ const std::string *cfg_raw_get(const Cfg &c, std::string_view k); bool internal_key(std::string_view k); Cfg get_cfg(std::string_view path); int set_cfg(std::string_view path, std::string_view key, std::string_view val); std::string config_path(); int fetch_context_window(Cfg &cfg); std::string list_models(Cfg &cfg, int *errout); std::string tools_dir(const Cfg &c); std::string skills_dir(const Cfg &c); /* ------------------------------------------------------------------ */ /* json.cpp — request building & response parsing (nlohmann/json). */ /* ------------------------------------------------------------------ */ std::string build_request_json(const Cfg &cfg, const Messages &msgs, bool use_tools, bool stream); bool parse_nonstream_response(std::string_view body, Message &out, Usage &usage); /* ------------------------------------------------------------------ */ /* llm.cpp — HTTP client (libcurl), headers, backoff, dispatch. */ /* ------------------------------------------------------------------ */ int http_get(Cfg &cfg, std::string_view url, std::string &body, long &code, std::string &errmsg); int llm(Cfg &cfg, Messages &msgs, bool use_tools, Message &out, Usage &usage, std::string &errmsg, volatile int *interrupted); /* ------------------------------------------------------------------ */ /* tools.cpp */ /* ------------------------------------------------------------------ */ std::string shell_with_workdir(std::string_view cmd, std::string_view workdir, int timeout, volatile int *interrupted); std::string read_file_or_dir(std::string_view path, int offset, int limit, int *style); std::string write_file(std::string_view path, int offset, int del_bytes, std::string_view content, int *err); std::string offload_tool_result(std::string_view res, int max_res, std::vector &tmps); void cleanup_temps(std::vector &tmps); /* ------------------------------------------------------------------ */ /* session.cpp */ /* ------------------------------------------------------------------ */ void save_session(const Messages &msgs, std::string_view sid, std::string *out_id, std::string *out_summary); std::vector sessions_load(); std::unique_ptr load_session(std::string_view sid, std::string *err); std::unique_ptr find_project_session(); void autosave(const Messages &msgs); std::unique_ptr compact(Cfg &cfg, const Messages &msgs, std::string *summary, std::string *err, volatile int *interrupted); std::string summary_of(const Messages &msgs); /* ------------------------------------------------------------------ */ /* render.cpp — terminal markdown rendering. */ /* ------------------------------------------------------------------ */ void render_md_print(std::string_view text); void render_md_line_print(std::string_view line, MdState &st); void render_table_print(const std::vector &lines); bool is_table_line(std::string_view line); /* ------------------------------------------------------------------ */ /* editor.cpp — GNU readline line editor + history (+ term helpers). */ /* ------------------------------------------------------------------ */ void load_history(); void save_history(); void add_history(std::string_view s); std::string read_line(std::string_view prompt, bool &ok); std::string read_plain(std::string_view prompt, bool &ok); int term_width(); #endif /* BANTAM_HPP */