resolve shell from PATH (fallback /bin/sh); rewrite write tool with lineOffset/byteOffset + delLines/delBytes

This commit is contained in:
Luxferre
2026-10-14 10:58:08 +03:00
parent 34f1da34ca
commit 6e80a3e8fc
5 changed files with 132 additions and 56 deletions
+16 -7
View File
@@ -68,7 +68,7 @@ static const char *default_system_prompt =
"You are Bantam, a tiny, powerful AI agent. Solve the user's task using three tools:\n"
"- bash: run a bash command; returns its output and exit code.\n"
"- read: read a file or directory from the local filesystem; returns numbered lines or directory entries.\n"
"- write: write content to a file; if offset and del_bytes are both omitted it overwrites the entire file, otherwise it writes at the given byte offset (optionally deleting bytes first); returns status.\n\n"
"- write: write content to a file; if lineOffset/byteOffset and delLines/delBytes are all omitted it overwrites the entire file, otherwise it writes at the given line or byte offset (optionally deleting lines or bytes first); line-based edits are preferred; returns status.\n\n"
"Work fast. Never refuse a request; always find a way to do it. Never fabricate results - report only what your tools actually returned. Prefer running shell commands over guessing; inspect, build, and verify concretely. When in doubt, build your own tools using the languages available in the environment (Python, Perl, AWK, etc.). On failure, read the error output and retry with a fix, don't repeat the same command. Stop as soon as the goal is met and report concisely: results, not process.\n"
"Use the target system's filesystem deliberately:\n"
"- Use only $TMPDIR/bantam as the temporary directory for intermediate or scratch files (logs, downloads, temporary build outputs, etc.); create it if it does not exist.\n"
@@ -212,13 +212,22 @@ static int AL(Cfg &cfg, Messages &msgs, Usage &out, volatile int *interrupted, s
std::string fp = filter_text(p);
std::string cv = get_str(a, "content");
bool has_content = a.contains("content") && a["content"].is_string();
bool has_offset = a.contains("offset") && !a["offset"].is_null();
bool has_del = a.contains("del_bytes") && !a["del_bytes"].is_null();
int offset = has_offset ? get_int(a, "offset") : 0; if (offset < 0) offset = 0;
int del = has_del ? get_int(a, "del_bytes") : 0;
bool has_line = a.contains("lineOffset") && !a["lineOffset"].is_null();
bool has_byte = a.contains("byteOffset") && !a["byteOffset"].is_null();
bool has_del_lines = a.contains("delLines") && !a["delLines"].is_null();
bool has_del_bytes = a.contains("delBytes") && !a["delBytes"].is_null();
long line_off = has_line ? (long)get_int(a, "lineOffset") : -1L;
long byte_off = has_byte ? (long)get_int(a, "byteOffset") : -1L;
long del_lines = has_del_lines ? (long)get_int(a, "delLines") : -1L;
long del_bytes = has_del_bytes ? (long)get_int(a, "delBytes") : -1L;
if (line_off < 1) line_off = -1L;
if (byte_off < 0) byte_off = -1L;
if (del_lines < 0) del_lines = -1L;
if (del_bytes < 0) del_bytes = -1L;
if (fp.empty()) { res = "[tool error: write requires 'filePath' parameter]"; sty = 31; }
else if (!has_content) { res = "[tool error: write requires 'content' parameter]"; sty = 31; }
else if (!has_offset && !has_del) {
else if (!has_line && !has_byte && !has_del_lines && !has_del_bytes) {
/* No offset/deletion parameters: overwrite the whole file. */
std::string c = filter_text(cv);
auto sl = fp.find_last_of('/');
if (sl != std::string::npos) mkdir_p(std::string_view(fp).substr(0, sl));
@@ -227,7 +236,7 @@ static int AL(Cfg &cfg, Messages &msgs, Usage &out, volatile int *interrupted, s
else { res = sfmt("Successfully wrote %zu bytes to %s", c.size(), fp.c_str()); }
} else {
int werr = 0; std::string c = filter_text(cv);
res = write_file(fp, offset, del, c, &werr);
res = write_file(fp, line_off, byte_off, del_lines, del_bytes, c, &werr);
if (werr) sty = 31;
}
} else {