@@ -555,8 +555,10 @@ static bool save_settings(const NitroConfig &cfg) {
555555 return f.good ();
556556}
557557
558+ //
558559// Trims whitespace from both ends of a string
559- std::string trim (std::string_view str) {
560+ //
561+ static std::string trim (std::string_view str) {
560562 const std::string_view whitespace = " \t\n\r\f\v " ;
561563
562564 // Find the first non-whitespace character
@@ -572,19 +574,44 @@ std::string trim(std::string_view str) {
572574 return std::string (str.substr (start, end - start + 1 ));
573575}
574576
577+ //
578+ // Removes any front and back characters
579+ //
580+ static std::string disclose (const std::string &input, char c1, char c2) {
581+ // Check if string has at least 2 characters
582+ if (input.length () < 2 ) {
583+ return input;
584+ }
585+
586+ // Check if first and last characters match the specified delimiters
587+ if (input[0 ] == c1 && input[input.length () - 1 ] == c2) {
588+ // Remove first and last characters
589+ std::string result = input;
590+ result.erase (0 , 1 );
591+ result.erase (input.length () - 1 , 1 );
592+ return result;
593+ }
594+
595+ return input;
596+ }
597+
575598// ─── colour helpers ──────────────────────────────────────────────────────
576599static constexpr uint32_t BG_CHAT_R = 18 , BG_CHAT_G = 22 , BG_CHAT_B = 30 ;
577600static constexpr uint32_t BG_INP_R = 22 , BG_INP_G = 28 , BG_INP_B = 38 ;
578601static constexpr uint32_t BG_HDR_R = 30 , BG_HDR_G = 40 , BG_HDR_B = 55 ;
602+
579603static inline uint64_t fg_rgb (uint32_t r, uint32_t g, uint32_t b) {
580604 return NCCHANNELS_INITIALIZER (r, g, b, 0 , 0 , 0 );
581605}
606+
582607static inline uint64_t chat_ch (uint32_t r, uint32_t g, uint32_t b) {
583608 return NCCHANNELS_INITIALIZER (r, g, b, BG_CHAT_R, BG_CHAT_G, BG_CHAT_B);
584609}
610+
585611static inline uint64_t inp_ch (uint32_t r, uint32_t g, uint32_t b) {
586612 return NCCHANNELS_INITIALIZER (r, g, b, BG_INP_R, BG_INP_G, BG_INP_B);
587613}
614+
588615static inline uint64_t hdr_ch (uint32_t r, uint32_t g, uint32_t b) {
589616 return NCCHANNELS_INITIALIZER (r, g, b, BG_HDR_R, BG_HDR_G, BG_HDR_B);
590617}
@@ -627,7 +654,10 @@ void TuiState::init() {
627654}
628655
629656void TuiState::destroy () {
630- if (nc) { notcurses_stop (nc); nc = nullptr ; }
657+ if (nc) {
658+ notcurses_stop (nc);
659+ nc = nullptr ;
660+ }
631661}
632662
633663void TuiState::resize () {
@@ -1445,10 +1475,16 @@ std::string AgentState::process_tool(const std::string &cmd, const NitroConfig &
14451475 }
14461476
14471477 auto resolve = [&](const std::string &p) -> std::string {
1448- if (p.empty () || p == " ." ) return sandbox;
1449- if (p.substr (0 , 2 ) == " ./" ) return join_path (sandbox, p.substr (2 ));
1450- if (p[0 ] == ' /' ) return p;
1451- return join_path (sandbox, p);
1478+ if (p.empty () || p == " ." ) {
1479+ return sandbox;
1480+ }
1481+ if (p.substr (0 , 2 ) == " ./" ) {
1482+ return join_path (sandbox, p.substr (2 ));
1483+ }
1484+ if (p[0 ] == ' /' ) {
1485+ return p;
1486+ }
1487+ return join_path (sandbox, disclose (disclose (p, ' <' , ' >' ), ' [' , ' ]' ));
14521488 };
14531489
14541490 tui.append_line (" [tool] → " + op);
@@ -1493,7 +1529,7 @@ std::string AgentState::process_tool(const std::string &cmd, const NitroConfig &
14931529 if (!tui.confirm_dialog (std::format (" Allow model to write {}?" , p))) {
14941530 return " ERROR: action prevented by user" ;
14951531 }
1496- std::string content = strip_code_fences (arg1, arg2);
1532+ std::string content = disclose ( strip_code_fences (arg1, arg2), ' ` ' , ' ` ' );
14971533 return write_file (p, content) ? " OK: written to " + arg1 : " ERROR: write failed for " + arg1;
14981534 }
14991535 if (op == " TOOL:CURL" ) {
@@ -1577,6 +1613,7 @@ bool AgentState::run_turn(const std::string &user_message, const NitroConfig &cf
15771613 auto invoke_tool = [&](const std::string &tool, const std::string_view template_str) -> void {
15781614 std::string result = process_tool (tool, cfg, tui);
15791615 std::string content = std::vformat (template_str, std::make_format_args (result));
1616+ log_write (" tool: [%s] result: [%s]" , tool.c_str (), result.c_str ());
15801617 if (!llama->add_message (*iter, " tool_result" , content)) {
15811618 tui.append_line (std::string (" [err] tool result inject: " ) + llama->last_error ());
15821619 tui.redraw_all ();
@@ -1948,7 +1985,9 @@ static std::string tool_curl(const std::string &url) {
19481985 if (http_code >= 400 ) {
19491986 return " ERROR: HTTP " + std::to_string (http_code) + " from " + url;
19501987 }
1951- if (body.empty ()) return " (empty response)" ;
1988+ if (body.empty ()) {
1989+ return " (empty response)" ;
1990+ }
19521991
19531992 // Strip HTML tags so the model receives clean plain text.
19541993 bool is_html = (content_type.find (" text/html" ) != std::string::npos)
@@ -1990,9 +2029,14 @@ static std::string build_system_prompt(const std::vector<std::string> &knowledge
19902029 " - Reason step-by-step inside <|think|> </|think|> (hidden from user).\n "
19912030 " - After each tool call, explain what you did in plain English.\n\n " ;
19922031 for (const auto &kf : knowledge_files) {
1993- std::ifstream f (kf);
1994- if (!f) continue ;
1995- std::ostringstream oss; oss << f.rdbuf ();
2032+ auto path = join_path (sandbox, kf);
2033+ std::ifstream f (path);
2034+ if (!f) {
2035+ continue ;
2036+ }
2037+ log_write (" loaded [%s]" , path.c_str ());
2038+ std::ostringstream oss;
2039+ oss << f.rdbuf ();
19962040 p += " ## Knowledge: " + kf + " \n " + oss.str () + " \n\n " ;
19972041 }
19982042 return p;
@@ -2226,8 +2270,9 @@ int main(int argc, char **argv) {
22262270 const char *home = getenv (" HOME" );
22272271 return std::string (home ? home : " ." ) + " /" + arg.substr (2 );
22282272 }
2229- if (arg.substr (0 , 2 ) == " ./" )
2273+ if (arg.substr (0 , 2 ) == " ./" ) {
22302274 return (fs::current_path (ec) / arg.substr (2 )).string ();
2275+ }
22312276 return arg;
22322277 };
22332278
0 commit comments