Files
tai/taicpp/tests/glue_ports.cpp
T
retoorandClaude Sonnet 5.5 9f790e3177 glue: wire every port, flag dispatch and REPL host so build/detz runs the real agent
Adapters in src/glue for all ports of agent/ports.h (store, runtime, shell, ui, mcp, skills,
plexer, tui, ops, scheduler db), llm log sink and box, repl::ReplHost over agent::Agent, cap-speak,
serve-mcp, telegram and tui-local seams. main.cpp dispatches the flags in tai.py main() order.
Tests: tests/glue_persist.py (real model, restart persistence, one-shot shell call), tests/glue_flags.py,
tests/glue_ports.cpp. Spec: docs/glue.md, gaps: docs/glue-issues.md.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 07:20:01 +01:00

148 lines
6.3 KiB
C++

// tests/glue_ports.cpp: unit checks of src/glue on a throwaway TAI_HOME (no model, no network).
//
// every port of agent::ports() is wired after AppBundle::open
// JsonBridge round trips between the module json types
// StoreAdapter: records, chunks, search, tags, edges, secrets, schedules, sessions through the StorePort
// SchedulerDbAdapter: claim_once is exclusive
// StdoutCapture and SysInfoProbe
//
// Build (from taicpp/, after `make` so build/src/**/*.o exist) and run, in sh:
// INC=""; for d in $(find src -type d); do INC="$INC -I$d"; done
// g++ -std=c++23 -Wall -Wextra -Ibuild/gen -Isrc $INC -I../../moloapp/src tests/glue_ports.cpp
// $(find build/src -name '*.o') -lsqlite3 -lcurl -lz -pthread -lutil -o build/glue_ports (one line)
// build/glue_ports
#include <unistd.h>
#include <cstdio>
#include <cstdlib>
#include <string>
#include "glue/app_bundle.h"
#include "glue/json_bridge.h"
#include "glue/stdout_capture.h"
#include "glue/sysinfo_probe.h"
using namespace detz;
static int g_checks = 0, g_fails = 0;
#define CHECK(cond) \
do { \
++g_checks; \
if (!(cond)) { \
++g_fails; \
std::fprintf(stderr, "FAIL %s:%d %s\n", __FILE__, __LINE__, #cond); \
} \
} while (0)
static void json_bridge() {
store::Json s = store::Json::loads(R"({"a": [1, 2.5, "x"], "b": {"c": null, "d": true}})");
json::Value v = glue::JsonBridge::value(s);
CHECK(v.get("a").size() == 3);
CHECK(v.get("b").get("d").as_bool());
CHECK(glue::JsonBridge::store(v).dumps() == s.dumps());
wire::Json w = glue::JsonBridge::wire(v);
CHECK(w.dumps() == s.dumps());
misc::Json m = glue::JsonBridge::misc(v);
CHECK(m.dumps() == s.dumps());
}
static void ports_wired(glue::AppBundle& b) {
agent::Ports& p = agent::ports();
CHECK(p.runtime && p.shell && p.ui && p.mcp && p.skills && p.plexer && p.tui && p.ops && p.scheduler_db);
CHECK(llm::log_sink() != nullptr);
CHECK(llm::box_port() != nullptr);
CHECK(b.agent().store == &b.store_port());
CHECK(!b.agent().messages.is_null() && b.agent().messages.size() >= 1);
CHECK(b.agent().messages.at(0).get("role").str() == "system");
// runtime port: a worker store is a second connection on the same vault
auto worker = p.runtime->open_store();
CHECK(worker != nullptr);
CHECK(worker->profile() == b.agent().profile || !worker->profile().empty());
}
static void store_port(glue::AppBundle& b) {
agent::StorePort& s = b.store_port();
std::string id = s.add_record("note", "glue title", "alpha beta gamma unique-token-9137", {"glue"}, "");
CHECK(id.rfind("mem:", 0) == 0);
s.add_chunks("record", id, {"alpha beta gamma unique-token-9137"}, "");
agent::Value read = s.read_record(id, 0, 100, "");
CHECK(read.is_object() && read.get("slice").str().find("unique-token-9137") != std::string::npos);
agent::Value hits = s.fts_search("unique-token-9137", {}, "", 5);
CHECK(hits.is_array() && hits.size() >= 1);
agent::Value found = s.search_records("glue", std::nullopt, {}, 5, "");
CHECK(found.is_array() && found.size() >= 1);
CHECK(s.item_tags(id, "").size() >= 1);
std::string other = s.add_record("note", "second", "second record", {}, "");
std::string edge = s.add_edge(id, other, agent::Value("linked"), "");
CHECK(!edge.empty());
CHECK(s.edges_for(id, "").size() >= 1);
CHECK(s.delete_record(id, ""));
CHECK(s.read_record(id, 0, 10, "").is_null());
s.save_secret("glue-secret", "value-1", agent::Value(), {}, "");
CHECK(s.load_secret("glue-secret", "").value_or("") == "value-1");
CHECK(s.list_secret_infos("").size() >= 1);
s.delete_secret("glue-secret", "");
CHECK(!s.load_secret("glue-secret", "").has_value());
int64_t sched = s.add_schedule("n", "do it", s.profile(), 0, "2999-01-01T00:00:00+00:00", 600, {});
CHECK(sched > 0);
CHECK(s.list_schedules("").size() >= 1);
s.remove_schedule(sched, "");
agent::Value msgs = agent::Value::array();
agent::Value m1 = agent::Value::object();
m1.set("role", "user");
m1.set("content", "hello glue");
msgs.push(m1);
s.save_session("glue-prof", msgs, "main", "ctx-test");
agent::Value back = s.load_session("glue-prof", "main", "ctx-test");
CHECK(back.size() == 1 && back.at(0).get("content").str() == "hello glue");
agent::Value rows = s.sql_rows("SELECT 1, 'x', NULL", agent::Value::array());
CHECK(rows.size() == 1 && rows.at(0).at(0).as_int() == 1 && rows.at(0).at(1).str() == "x" && rows.at(0).at(2).is_null());
}
static void scheduler_port(glue::AppBundle& b) {
agent::StorePort& s = b.store_port();
int64_t id = s.add_schedule("", "run once", s.profile(), 0, "2000-01-01T00:00:00+00:00", 600, {});
auto due = b.scheduler_db().select_due("2001-01-01T00:00:00+00:00");
bool seen = false;
for (const auto& d : due) if (d.id == id) seen = true;
CHECK(seen);
CHECK(b.scheduler_db().claim_once(id, "2001-01-01T00:00:00+00:00"));
CHECK(!b.scheduler_db().claim_once(id, "2001-01-01T00:00:01+00:00"));
b.scheduler_db().note_result(id, "done", "ok");
s.remove_schedule(id, "");
}
static void helpers() {
{
glue::StdoutCapture cap;
std::printf("captured-line\n");
std::string out = cap.finish();
CHECK(out == "captured-line\n");
}
std::string info = glue::SysInfoProbe::collect(std::vector<std::string>{"cpu", "root"});
CHECK(info.find("cpu: ") != std::string::npos && info.find("root: ") != std::string::npos && info.find("os: ") == std::string::npos);
}
int main() {
char dir[] = "/tmp/detz-glue-ports-XXXXXX";
if (!mkdtemp(dir)) return 2;
setenv("TAI_HOME", dir, 1);
setenv("HOME", dir, 1);
setenv("TAI_PASSPHRASE", "", 1);
json_bridge();
helpers();
glue::BundleOptions o;
o.version = "test";
o.mode = "test";
auto bundle = glue::AppBundle::open(o);
ports_wired(*bundle);
store_port(*bundle);
scheduler_port(*bundle);
bundle.reset();
CHECK(agent::ports().shell == nullptr); // the bundle clears the ports
std::printf("%d checks, %d failures\n", g_checks, g_fails);
return g_fails ? 1 : 0;
}