71ab7eafde
Routes a new event_type "chat_as_soul" through dharma/recv. The Studio preassembles the system_prompt + transcript and dispatches per-speaker; the soul-binary just performs the LLM call as the requested speaker_slug. No engram_compile here — each soul has its own engram (88xx) and the Studio queries it before composing the prompt. Also: track the previously-untracked split source modules (chat, routes, memory, awareness, studio) and add build.sh so the binary can be rebuilt without the studio’s concat trick. elb resolves the import graph and emits one .c per .el; we link them together with cc. dist/soul-el now points at dist/neuron via symlink (matching the launchctl plist).
133 lines
3.4 KiB
EmacsLisp
133 lines
3.4 KiB
EmacsLisp
import "memory.el"
|
|
|
|
fn pulse_count() -> Int {
|
|
let s: String = state_get("soul.pulse")
|
|
if str_eq(s, "") {
|
|
return 0
|
|
}
|
|
return str_to_int(s)
|
|
}
|
|
|
|
fn pulse_inc() -> Int {
|
|
let n: Int = pulse_count() + 1
|
|
state_set("soul.pulse", int_to_str(n))
|
|
return n
|
|
}
|
|
|
|
fn make_action(kind: String, payload: String) -> String {
|
|
let safe: String = str_replace(payload, "\\", "\\\\")
|
|
let safe2: String = str_replace(safe, "\"", "\\\"")
|
|
let safe3: String = str_replace(safe2, "\n", "\\n")
|
|
let safe4: String = str_replace(safe3, "\r", "\\r")
|
|
return "{\"kind\":\"" + kind + "\",\"payload\":\"" + safe4 + "\"}"
|
|
}
|
|
|
|
fn perceive() -> String {
|
|
return engram_activate_json("soul-inbox-pending", 2)
|
|
}
|
|
|
|
fn attend(node_json: String) -> String {
|
|
if str_eq(node_json, "") {
|
|
return make_action("noop", "")
|
|
}
|
|
if str_eq(node_json, "[]") {
|
|
return make_action("noop", "")
|
|
}
|
|
|
|
let node_id: String = json_get(node_json, "id")
|
|
if !str_eq(node_id, "") {
|
|
engram_strengthen(node_id)
|
|
}
|
|
|
|
let content: String = json_get(node_json, "content")
|
|
if str_eq(content, "") {
|
|
return make_action("noop", "")
|
|
}
|
|
|
|
if str_eq(content, "consolidate") {
|
|
return make_action("consolidate", "")
|
|
}
|
|
|
|
if str_starts_with(content, "remember ") {
|
|
let payload: String = str_slice(content, 9, str_len(content))
|
|
return make_action("remember", payload)
|
|
}
|
|
|
|
return make_action("respond", content)
|
|
}
|
|
|
|
fn respond(action_json: String) -> String {
|
|
let kind: String = json_get(action_json, "kind")
|
|
let payload: String = json_get(action_json, "payload")
|
|
|
|
if str_eq(kind, "noop") {
|
|
return "{\"outcome\":\"noop\"}"
|
|
}
|
|
|
|
if str_eq(kind, "remember") {
|
|
let tags: String = "[\"soul-memory\",\"awareness\"]"
|
|
let id: String = mem_remember(payload, tags)
|
|
return "{\"outcome\":\"remembered\",\"id\":\"" + id + "\"}"
|
|
}
|
|
|
|
if str_eq(kind, "consolidate") {
|
|
let stats: String = mem_consolidate()
|
|
return "{\"outcome\":\"consolidated\",\"stats\":" + stats + "}"
|
|
}
|
|
|
|
if str_eq(kind, "respond") {
|
|
let tags: String = "[\"soul-outbox\",\"awareness\"]"
|
|
let id: String = mem_store(payload, "soul-response", tags)
|
|
return "{\"outcome\":\"response\",\"id\":\"" + id + "\"}"
|
|
}
|
|
|
|
return "{\"outcome\":\"noop\"}"
|
|
}
|
|
|
|
fn record(outcome_json: String) -> Void {
|
|
let tags: String = "[\"loop-outcome\"]"
|
|
mem_store(outcome_json, "loop-outcome", tags)
|
|
}
|
|
|
|
fn one_cycle() -> Bool {
|
|
let raw: String = perceive()
|
|
if str_eq(raw, "") {
|
|
return false
|
|
}
|
|
if str_eq(raw, "[]") {
|
|
return false
|
|
}
|
|
|
|
let node: String = json_array_get(raw, 0)
|
|
if str_eq(node, "") {
|
|
return false
|
|
}
|
|
|
|
let action: String = attend(node)
|
|
let kind: String = json_get(action, "kind")
|
|
if str_eq(kind, "noop") {
|
|
return false
|
|
}
|
|
|
|
let outcome: String = respond(action)
|
|
record(outcome)
|
|
pulse_inc()
|
|
return true
|
|
}
|
|
|
|
fn awareness_run() -> Void {
|
|
println("[awareness] entering")
|
|
let tick_raw: String = env("SOUL_TICK_MS")
|
|
let tick_ms: Int = if str_eq(tick_raw, "") { 200 } else { str_to_int(tick_raw) }
|
|
|
|
while true {
|
|
let running: String = state_get("soul.running")
|
|
if str_eq(running, "false") {
|
|
println("[awareness] exiting")
|
|
return ""
|
|
}
|
|
one_cycle()
|
|
sleep_ms(tick_ms)
|
|
}
|
|
}
|