Optimize startup, HTTP/SSE streaming, and fix macOS libedit bindings

This commit is contained in:
Luxferre
2026-10-14 15:30:12 +03:00
parent 105d283e01
commit a1d5f4bf48
10 changed files with 497 additions and 222 deletions
+47 -42
View File
@@ -1,5 +1,6 @@
/* session.cpp — session persistence, loading, compaction. */
#include "bantam.hpp"
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
@@ -24,6 +25,29 @@ static std::string sessions_dir() {
return d;
}
static bool load_session_file(const std::string &full, Session &s) {
std::string buf;
if (!read_file_str(full, buf)) return false;
Json root_mut;
if (!Json::parse(buf, root_mut) || !root_mut.is_object()) return false;
const Json &root = root_mut;
s = Session{};
s.id = root["id"].str();
s.created = root["created"].str();
s.summary = root["summary"].str();
const Json &marr = root["messages"];
if (marr.is_array()) {
s.messages.items.reserve(marr.aval.size());
for (auto &mo : marr.aval) {
Message m;
parse_message_json(mo, m);
s.messages.items.push_back(std::move(m));
}
}
if (s.summary.empty()) s.summary = "(no summary)";
return true;
}
void save_session(const Messages &msgs, std::string_view sid,
std::string *out_id, std::string *out_summary) {
std::string id = (!sid.empty()) ? std::string(sid) : project_id();
@@ -40,6 +64,7 @@ void save_session(const Messages &msgs, std::string_view sid,
std::string sum = summary_of(msgs);
root["summary"] = sum;
Json arr = Json::array();
arr.aval.reserve(msgs.items.size());
for (auto &m : msgs.items) {
Json mo;
serialize_message_json(mo, m);
@@ -63,63 +88,46 @@ std::vector<Session> sessions_load() {
std::string nm = de->d_name;
if (nm == "." || nm == "..") continue;
if (nm.size() < 5 || nm.substr(nm.size() - 5) != ".json") continue;
files.push_back(nm);
files.push_back(std::move(nm));
}
closedir(dir);
}
}
for (size_t i = 1; i < files.size(); i++) {
for (size_t j = i; j > 0 && files[j - 1] > files[j]; j--) {
std::swap(files[j - 1], files[j]);
}
}
std::sort(files.begin(), files.end());
ss.reserve(files.size());
for (auto &nm : files) {
std::string full = d + "/" + nm;
std::string buf;
if (!read_file_str(full, buf)) continue;
Json root_mut;
if (!Json::parse(buf, root_mut) || !root_mut.is_object()) continue;
const Json &root = root_mut;
Session s;
s.id = root["id"].str();
s.created = root["created"].str();
s.summary = root["summary"].str();
const Json &marr = root["messages"];
if (marr.is_array()) {
for (auto &mo : marr.aval) {
Message m;
parse_message_json(mo, m);
s.messages.items.push_back(std::move(m));
}
if (load_session_file(full, s)) {
ss.push_back(std::move(s));
}
if (s.summary.empty()) s.summary = "(no summary)";
ss.push_back(std::move(s));
}
/* sort by id descending (newest first) */
for (size_t i = 1; i < ss.size(); i++) {
for (size_t j = i; j > 0 && ss[j - 1].id < ss[j].id; j--) {
std::swap(ss[j - 1], ss[j]);
}
}
std::sort(ss.begin(), ss.end(), [](const Session &a, const Session &b) {
return a.id > b.id;
});
return ss;
}
std::unique_ptr<Messages> load_session(std::string_view sid, std::string *err) {
if (!sid.empty() && sid.find('/') == std::string_view::npos) {
std::string exact = sessions_dir() + "/" + std::string(sid) + ".json";
Session s;
if (load_session_file(exact, s) && s.id == sid) {
return std::make_unique<Messages>(std::move(s.messages));
}
}
auto ss = sessions_load();
for (auto &s : ss) {
if (s.id == sid) {
auto res = std::make_unique<Messages>();
for (auto &m : s.messages.items) res->items.push_back(m);
return res;
return std::make_unique<Messages>(std::move(s.messages));
}
}
/* prefix match */
std::vector<Session *> pref;
for (auto &s : ss) if (s.id.rfind(sid, 0) == 0) pref.push_back(&s);
for (auto &s : ss) if (s.id.starts_with(sid)) pref.push_back(&s);
if (pref.size() == 1) {
auto res = std::make_unique<Messages>();
for (auto &m : pref[0]->messages.items) res->items.push_back(m);
return res;
return std::make_unique<Messages>(std::move(pref[0]->messages));
}
if (pref.size() > 1) {
std::string names;
@@ -134,13 +142,10 @@ std::unique_ptr<Messages> load_session(std::string_view sid, std::string *err) {
std::unique_ptr<Session> find_project_session() {
std::string pid = project_id();
auto ss = sessions_load();
for (auto &s : ss) {
if (s.id == pid) {
auto found = std::make_unique<Session>();
*found = std::move(s);
return found;
}
std::string path = sessions_dir() + "/" + pid + ".json";
auto found = std::make_unique<Session>();
if (load_session_file(path, *found) && found->id == pid) {
return found;
}
return nullptr;
}