#include "tui_control.h" #include "../llm/proc.h" #include "../llm/py.h" #include "text.h" #include #include #include #include #include #include namespace detz::agent { std::string grr_control_path() { std::string home = llm::env_get("TAI_HOME"); if (home.empty()) { home = expanduser("~") + "/.tai"; } std::string sock = llm::env_get("TAI_TUI_SOCK"); return !sock.empty() ? sock : home + "/tui.sock"; } json::Value grr_control_call(const json::Value& payload, const std::string& path_in, double timeout) { std::string path = path_in.empty() ? grr_control_path() : path_in; auto failure = [&](const std::string& what) { json::Value o = json::Value::object(); o.set("state", "error"); o.set("error", "no running grr TUI answers on " + path + " (" + what + ")"); return o; }; int fd = ::socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { return failure(std::string("[Errno ") + std::to_string(errno) + "] " + std::strerror(errno)); } struct sockaddr_un addr{}; addr.sun_family = AF_UNIX; if (path.size() >= sizeof addr.sun_path) { ::close(fd); return failure("AF_UNIX path too long"); } std::memcpy(addr.sun_path, path.c_str(), path.size() + 1); if (::connect(fd, reinterpret_cast(&addr), sizeof addr) != 0) { int err = errno; ::close(fd); return failure("[Errno " + std::to_string(err) + "] " + std::strerror(err)); } std::string line = payload.dumps() + "\n"; size_t off = 0; while (off < line.size()) { ssize_t w = ::send(fd, line.data() + off, line.size() - off, MSG_NOSIGNAL); if (w < 0) { if (errno == EINTR) { continue; } int err = errno; ::close(fd); return failure("[Errno " + std::to_string(err) + "] " + std::strerror(err)); } off += static_cast(w); } std::string data; while (data.empty() || data.back() != '\n') { struct pollfd pfd{fd, POLLIN, 0}; int pr = ::poll(&pfd, 1, static_cast(timeout * 1000)); if (pr == 0) { ::close(fd); return failure("timed out"); } if (pr < 0) { if (errno == EINTR) { continue; } int err = errno; ::close(fd); return failure("[Errno " + std::to_string(err) + "] " + std::strerror(err)); } char buf[65536]; ssize_t c = ::recv(fd, buf, sizeof buf, 0); if (c < 0) { if (errno == EINTR) { continue; } int err = errno; ::close(fd); return failure("[Errno " + std::to_string(err) + "] " + std::strerror(err)); } if (c == 0) { break; } data.append(buf, static_cast(c)); } ::close(fd); try { return json::Value::loads(py::utf8_replace(data)); } catch (const json::ParseError&) { json::Value o = json::Value::object(); o.set("state", "error"); o.set("error", "unreadable reply"); return o; } } } // namespace detz::agent