Spaces:
Sleeping
Sleeping
File size: 10,135 Bytes
84b52f0 a3f913d 84b52f0 a3f913d 84b52f0 a3f913d 84b52f0 a3f913d 84b52f0 a3f913d 84b52f0 a3f913d 84b52f0 a3f913d 84b52f0 a3f913d 84b52f0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | #include "cognition/llama_bridge.h"
#include <llama.h>
#include <vector>
#include <stdexcept>
namespace tbv {
// Run 2 Plan §B4 — truncated fragments (mid-sentence cuts from the token cap) were
// entering memory stores and getting re-mutated forever; visible to every real visitor.
// Finds the LAST sentence terminator and truncates just after it (absorbing one
// immediately-following closing quote/paren, since a terminator often hides behind
// one -- e.g. `he said "stop."` ). If no terminator exists at all, the text is left
// untouched -- never return an empty string just because generation never finished
// a sentence within budget.
static void trim_to_sentence(std::string& s) {
static const std::string closers = "\"')"; // ASCII closers only -- avoid UTF-8 byte-match foot-guns
for (size_t i = s.size(); i-- > 0; ) {
char c = s[i];
if (c == '.' || c == '!' || c == '?') {
size_t end = i + 1;
if (end < s.size() && closers.find(s[end]) != std::string::npos) end++;
if (end < s.size()) s.erase(end);
return;
}
}
// no terminator found -- keep raw, don't manufacture an empty string
}
LlamaBridge::LlamaBridge(const std::string& model_path) {
llama_backend_init();
llama_model_params mparams = llama_model_default_params();
model = llama_model_load_from_file(model_path.c_str(), mparams);
if (!model) throw std::runtime_error("Failed to load llama model");
vocab = llama_model_get_vocab(model);
llama_context_params cparams = llama_context_default_params();
cparams.n_ctx = 2048; // re-sized: ~160-tok thought + intent fits; revisit for concurrency
cparams.n_threads = 1;
cparams.n_threads_batch = 1;
ctx = llama_init_from_model(model, cparams);
if (!ctx) throw std::runtime_error("Failed to create llama context");
}
LlamaBridge::~LlamaBridge() {
if (ctx) llama_free(ctx);
if (model) llama_model_free(model);
llama_backend_free();
}
// Decode a raw string into the active context (appends, no KV reset).
static void decode_str(llama_context* ctx, const llama_vocab* vocab, llama_batch& b,
int32_t& pos, const std::string& s, bool add_bos) {
std::vector<llama_token> t(s.size() + 16);
int n = llama_tokenize(vocab, s.c_str(), s.length(), t.data(), t.size(), add_bos, true);
if (n < 0) { t.resize(-n); n = llama_tokenize(vocab, s.c_str(), s.length(), t.data(), t.size(), add_bos, true); }
t.resize(n);
b.n_tokens = 0;
for (int i = 0; i < n; ++i) {
b.token[b.n_tokens] = t[i]; b.pos[b.n_tokens] = pos++;
b.n_seq_id[b.n_tokens] = 1; b.seq_id[b.n_tokens][0] = 0;
b.logits[b.n_tokens] = (i == n - 1); b.n_tokens++;
}
llama_decode(ctx, b);
}
// Free (un-grammared) generation segment. Returns text.
static std::string gen(llama_context* ctx, const llama_vocab* vocab, llama_batch& b,
int32_t& pos, llama_sampler* chain, int max_tokens) {
std::string out; int n_vocab = llama_vocab_n_tokens(vocab);
for (int i = 0; i < max_tokens; ++i) {
float* lg = llama_get_logits_ith(ctx, b.n_tokens - 1);
if (!lg) break;
std::vector<llama_token_data> cd; cd.reserve(n_vocab);
for (llama_token t = 0; t < n_vocab; ++t) cd.push_back(llama_token_data{t, lg[t], 0.0f});
llama_token_data_array cp = { cd.data(), cd.size(), -1, false };
llama_sampler_apply(chain, &cp);
llama_token nt = (cp.selected != -1) ? cp.data[cp.selected].id : cp.data[0].id;
llama_sampler_accept(chain, nt);
if (llama_vocab_is_eog(vocab, nt)) break;
char buf[128]; int nc = llama_token_to_piece(vocab, nt, buf, sizeof(buf), 0, true);
if (nc > 0) out.append(buf, nc);
b.n_tokens = 0; b.token[0] = nt; b.pos[0] = pos++;
b.n_seq_id[0] = 1; b.seq_id[0][0] = 0; b.logits[0] = true; b.n_tokens = 1;
if (llama_decode(ctx, b) != 0) break;
}
return out;
}
Cognition LlamaBridge::infer(VillagerID id, const PerceptionContext& pc, uint64_t seed) {
(void)id;
// ChatML-wrap the grounded situation.
llama_chat_message msg[1]; msg[0].role = "user"; msg[0].content = pc.situation.c_str();
const char* tmpl = llama_model_chat_template(model, nullptr);
std::vector<char> tp(pc.situation.size() + 1024);
int r = llama_chat_apply_template(tmpl, msg, 1, true, tp.data(), tp.size());
if (r > (int)tp.size()) { tp.resize(r); r = llama_chat_apply_template(tmpl, msg, 1, true, tp.data(), tp.size()); }
std::string prompt = (r > 0) ? std::string(tp.data()) : pc.situation;
// Fresh context per call keeps determinism + isolates KV (Phase 1).
llama_memory_t mem = llama_get_memory(ctx);
llama_memory_seq_rm(mem, 0, -1, -1);
llama_batch b = llama_batch_init(2048, 0, 1);
int32_t pos = 0;
decode_str(ctx, vocab, b, pos, prompt, true);
llama_sampler_chain_params sp = llama_sampler_chain_default_params();
llama_sampler* chain = llama_sampler_chain_init(sp);
llama_sampler_chain_add(chain, llama_sampler_init_penalties(200, 1.15f, 0.0f, 0.0f));
llama_sampler_chain_add(chain, llama_sampler_init_top_k(50));
llama_sampler_chain_add(chain, llama_sampler_init_top_p(0.9, 1));
llama_sampler_chain_add(chain, llama_sampler_init_temp(0.8));
llama_sampler_chain_add(chain, llama_sampler_init_dist(seed));
// Segment 1: free thought.
std::string thought = gen(ctx, vocab, b, pos, chain, n_thought_cap);
trim_to_sentence(thought); // §B4 -- thought only, never intent (resolver needs the raw text)
// Free intent micro-gen (fresh user turn, same context).
decode_str(ctx, vocab, b, pos,
"<|im_end|>\n<|im_start|>user\nIn one short sentence, what do you physically do right now?<|im_end|>\n<|im_start|>assistant\nI ", false);
std::string intent = gen(ctx, vocab, b, pos, chain, 28);
llama_sampler_free(chain);
llama_batch_free(b);
llama_memory_seq_rm(mem, 0, -1, -1);
Resolved res = resolve(intent, pc.needs, pc.env);
return { thought, intent, res.verb, res.source };
}
RetellResult LlamaBridge::retell(VillagerID id, const std::string& heard,
const std::string& persona, uint64_t seed) {
(void)id;
std::string user = persona + "You overhear someone in the village saying: \"" + heard +
"\" In your own words, what do you make of it and pass along to others?";
llama_chat_message msg[1]; msg[0].role = "user"; msg[0].content = user.c_str();
const char* tmpl = llama_model_chat_template(model, nullptr);
std::vector<char> tp(user.size() + 1024);
int r = llama_chat_apply_template(tmpl, msg, 1, true, tp.data(), tp.size());
if (r > (int)tp.size()) { tp.resize(r); r = llama_chat_apply_template(tmpl, msg, 1, true, tp.data(), tp.size()); }
std::string prompt = (r > 0) ? std::string(tp.data()) : user;
llama_memory_t mem = llama_get_memory(ctx);
llama_memory_seq_rm(mem, 0, -1, -1);
llama_batch b = llama_batch_init(2048, 0, 1);
int32_t pos = 0;
decode_str(ctx, vocab, b, pos, prompt, true);
llama_sampler_chain_params sp = llama_sampler_chain_default_params();
llama_sampler* chain = llama_sampler_chain_init(sp);
llama_sampler_chain_add(chain, llama_sampler_init_penalties(200, 1.15f, 0.0f, 0.0f));
llama_sampler_chain_add(chain, llama_sampler_init_top_k(50));
llama_sampler_chain_add(chain, llama_sampler_init_top_p(0.9, 1));
llama_sampler_chain_add(chain, llama_sampler_init_temp(0.8));
llama_sampler_chain_add(chain, llama_sampler_init_dist(seed));
std::string out = gen(ctx, vocab, b, pos, chain, 90);
trim_to_sentence(out); // §B4 -- MUST happen before hearsay_hop's forced-novelty append
// (live evidence tick 31908: distortion glued onto a truncated
// sentence with no boundary between them)
llama_sampler_free(chain);
llama_batch_free(b);
llama_memory_seq_rm(mem, 0, -1, -1);
// Segment 2: structured extraction from the free reconstruction (deterministic).
RetellResult rr;
rr.out_text = out;
rr.fields = extract_hearsay_fields(out);
return rr;
}
std::string LlamaBridge::dream(VillagerID id, const std::vector<std::string>& fragments,
const std::string& persona, uint64_t seed) {
(void)id;
std::string frag;
for (size_t i = 0; i < fragments.size(); ++i) frag += "\n- \"" + fragments[i] + "\"";
std::string user = persona + "You drift into sleep. Fragments of your memories swirl together:" + frag +
"\nDescribe the strange, surreal dream that forms from them.";
llama_chat_message msg[1]; msg[0].role = "user"; msg[0].content = user.c_str();
const char* tmpl = llama_model_chat_template(model, nullptr);
std::vector<char> tp(user.size() + 1024);
int r = llama_chat_apply_template(tmpl, msg, 1, true, tp.data(), tp.size());
if (r > (int)tp.size()) { tp.resize(r); r = llama_chat_apply_template(tmpl, msg, 1, true, tp.data(), tp.size()); }
std::string prompt = (r > 0) ? std::string(tp.data()) : user;
llama_memory_t mem = llama_get_memory(ctx);
llama_memory_seq_rm(mem, 0, -1, -1);
llama_batch b = llama_batch_init(2048, 0, 1);
int32_t pos = 0;
decode_str(ctx, vocab, b, pos, prompt, true);
llama_sampler_chain_params sp = llama_sampler_chain_default_params();
llama_sampler* chain = llama_sampler_chain_init(sp);
llama_sampler_chain_add(chain, llama_sampler_init_penalties(200, 1.15f, 0.0f, 0.0f));
llama_sampler_chain_add(chain, llama_sampler_init_top_k(50));
llama_sampler_chain_add(chain, llama_sampler_init_top_p(0.9, 1));
llama_sampler_chain_add(chain, llama_sampler_init_temp(0.9)); // hotter -> more surreal
llama_sampler_chain_add(chain, llama_sampler_init_dist(seed));
std::string out = gen(ctx, vocab, b, pos, chain, 100);
trim_to_sentence(out); // §B4
llama_sampler_free(chain);
llama_batch_free(b);
llama_memory_seq_rm(mem, 0, -1, -1);
return out;
}
} // namespace tbv
|