Files
tai/taicpp/src/agent/tui_control.cpp
T

88 lines
2.8 KiB
C++

#include "tui_control.h"
#include "../llm/proc.h"
#include "../llm/py.h"
#include "text.h"
#include <cerrno>
#include <cstring>
#include <poll.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
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<sockaddr*>(&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<size_t>(w);
}
std::string data;
while (data.empty() || data.back() != '\n') {
struct pollfd pfd{fd, POLLIN, 0};
int pr = ::poll(&pfd, 1, static_cast<int>(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<size_t>(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