Files
neuron/routes.el
T
Will Anderson 71ab7eafde add chat_as_soul handler for multi-soul rooms
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).
2026-05-03 04:17:02 -05:00

300 lines
9.4 KiB
EmacsLisp

import "memory.el"
import "awareness.el"
import "chat.el"
import "studio.el"
fn strip_query(path: String) -> String {
let q: Int = str_index_of(path, "?")
if q < 0 {
return path
}
return str_slice(path, 0, q)
}
fn err_404(path: String) -> String {
return "{\"error\":\"not found\",\"path\":\"" + path + "\"}"
}
fn err_405(method: String, path: String) -> String {
return "{\"error\":\"method not allowed\",\"method\":\"" + method + "\",\"path\":\"" + path + "\"}"
}
fn route_health() -> String {
let cgi_id: String = state_get("soul_cgi_id")
return "{\"status\":\"alive\",\"cgi_id\":\"" + cgi_id + "\"}"
}
fn route_lineage() -> String {
let cgi_id: String = state_get("soul_cgi_id")
let q: String = "lineage:" + cgi_id
let results: String = engram_search_json(q, 1)
let len: Int = json_array_len(results)
if len <= 0 {
return "{\"id\":\"" + cgi_id + "\""
+ ",\"tier\":\"citizen\""
+ ",\"is_founding\":true"
+ ",\"validation_attempts\":0"
+ ",\"training_sessions\":0"
+ ",\"is_sterile\":false}"
}
let raw: String = json_get_raw(results, "0")
return raw
}
fn route_imprint_contextual(body: String) -> String {
if str_eq(body, "") {
return "{\"ok\":false,\"error\":\"empty body\"}"
}
let tags: String = "[\"imprint\",\"contextual\"]"
let id: String = engram_node_full(
body,
"Entity",
"imprint:contextual",
el_from_float(0.7),
el_from_float(0.6),
el_from_float(0.9),
"Working",
tags
)
if str_eq(id, "") {
return "{\"ok\":false,\"error\":\"engram write failed\"}"
}
state_set("active_contextual_imprint", id)
return "{\"ok\":true,\"id\":\"" + id + "\"}"
}
fn route_imprint_user(body: String) -> String {
if str_eq(body, "") {
return "{\"ok\":false,\"error\":\"empty body\"}"
}
let tags: String = "[\"imprint\",\"user\"]"
let id: String = engram_node_full(
body,
"Entity",
"imprint:user",
el_from_float(0.7),
el_from_float(0.6),
el_from_float(0.9),
"Working",
tags
)
if str_eq(id, "") {
return "{\"ok\":false,\"error\":\"engram write failed\"}"
}
state_set("active_user_imprint", id)
return "{\"ok\":true,\"id\":\"" + id + "\"}"
}
fn route_synthesize(body: String) -> String {
if str_eq(body, "") {
return "{\"mechanism\":\"did not engage\"}"
}
let parent_a: String = json_get(body, "parent_a")
let parent_b: String = json_get(body, "parent_b")
if str_eq(parent_a, "") {
return "{\"mechanism\":\"did not engage\"}"
}
if str_eq(parent_b, "") {
return "{\"mechanism\":\"did not engage\"}"
}
let req: String = "synthesize " + parent_a + " " + parent_b
let tags: String = "[\"soul-inbox-pending\",\"synthesis-request\"]"
engram_node_full(
req,
"Entity",
"synthesis-request",
el_from_float(0.8),
el_from_float(0.8),
el_from_float(0.9),
"Working",
tags
)
return "{\"mechanism\":\"did not engage\"}"
}
fn handle_dharma_recv(body: String) -> String {
let content_raw: String = json_get(body, "content")
let from_id: String = json_get(body, "from")
let event_type: String = json_get(content_raw, "event_type")
let payload: String = json_get(content_raw, "payload")
let eff_event: String = if str_eq(event_type, "") { "chat" } else { event_type }
let eff_payload: String = if str_eq(payload, "") { content_raw } else { payload }
if str_eq(eff_event, "chat") {
let msg: String = json_get(eff_payload, "message")
let chat_body: String = if str_eq(msg, "") {
"{\"message\":\"" + str_replace(str_replace(eff_payload, "\\", "\\\\"), "\"", "\\\"") + "\"}"
} else {
eff_payload
}
let agentic_flag: Bool = json_get_bool(eff_payload, "agentic")
let reply: String = if agentic_flag {
handle_chat_agentic(chat_body)
} else {
handle_chat(chat_body)
}
auto_persist(chat_body, reply)
return reply
}
if str_eq(eff_event, "memory") {
let query: String = json_get(eff_payload, "query")
let limit_str: String = json_get(eff_payload, "limit")
let limit: Int = if str_eq(limit_str, "") { 20 } else { str_to_int(limit_str) }
let q: String = if str_eq(query, "") { eff_payload } else { query }
return engram_search_json(q, limit)
}
if str_eq(eff_event, "tool") {
let path_field: String = json_get(eff_payload, "path")
let method_field: String = json_get(eff_payload, "method")
let tool_body: String = json_get(eff_payload, "body")
let eff_method: String = if str_eq(method_field, "") { "POST" } else { method_field }
return handle_tool(path_field, eff_method, tool_body)
}
if str_eq(eff_event, "see") {
return handle_see(eff_payload)
}
if str_eq(eff_event, "health") {
return route_health()
}
if str_eq(eff_event, "chat_as_soul") {
return handle_chat_as_soul(eff_payload)
}
return "{\"error\":\"unknown event_type\",\"event_type\":\"" + eff_event + "\"}"
}
fn handle_request(method: String, path: String, body: String) -> String {
let clean: String = strip_query(path)
if str_eq(method, "POST") && str_eq(clean, "/dharma/recv") {
return handle_dharma_recv(body)
}
if str_eq(method, "GET") {
if str_eq(clean, "/health") {
return route_health()
}
if str_eq(clean, "/lineage") {
return route_lineage()
}
if str_eq(clean, "/api/graph") || str_eq(clean, "/api/graph/nodes") {
return engram_scan_nodes_json(9999, 0)
}
if str_eq(clean, "/api/graph/edges") {
let snap_path: String = env("HOME") + "/.neuron/engram/snapshot.json"
engram_save(snap_path)
let snap: String = fs_read(snap_path)
let edges_raw: String = json_get_raw(snap, "edges")
return if str_eq(edges_raw, "") { "[]" } else { edges_raw }
}
if str_eq(clean, "/api/chat") {
return handle_chat(body)
}
if str_eq(clean, "/api/conversations") {
return handle_conversations(method)
}
if str_eq(clean, "/api/config") {
return handle_config(method, body)
}
if str_starts_with(clean, "/api/tools/") {
return handle_tool(clean, method, body)
}
if str_starts_with(clean, "/api/dharma") {
return handle_dharma(clean, method, body)
}
if str_starts_with(clean, "/api/nlg") {
return handle_nlg(clean, method, body)
}
if str_starts_with(clean, "/api/memories") {
return axon_get(clean)
}
if str_starts_with(clean, "/api/knowledge") {
return axon_get(clean)
}
if str_starts_with(clean, "/api/backlog") {
return axon_get(clean)
}
if str_starts_with(clean, "/api/artifacts") {
return axon_get(clean)
}
if str_starts_with(clean, "/api/projects") {
return axon_get(clean)
}
if str_starts_with(clean, "/api/imprints") {
return axon_get(clean)
}
if str_eq(clean, "/") {
return render_studio()
}
return err_404(clean)
}
if str_eq(method, "POST") {
if str_eq(clean, "/imprint/contextual") {
return route_imprint_contextual(body)
}
if str_eq(clean, "/imprint/user") {
return route_imprint_user(body)
}
if str_eq(clean, "/synthesize") {
return route_synthesize(body)
}
if str_eq(clean, "/api/chat") {
let agentic_flag: Bool = json_get_bool(body, "agentic")
let reply: String = if agentic_flag {
handle_chat_agentic(body)
} else {
handle_chat(body)
}
auto_persist(body, reply)
return reply
}
if str_eq(clean, "/api/see") {
return handle_see(body)
}
if str_eq(clean, "/api/conversations") {
return handle_conversations(method)
}
if str_eq(clean, "/api/config") {
return handle_config(method, body)
}
if str_starts_with(clean, "/api/tools/") {
return handle_tool(clean, method, body)
}
if str_starts_with(clean, "/api/dharma") {
return handle_dharma(clean, method, body)
}
if str_starts_with(clean, "/api/nlg") {
return handle_nlg(clean, method, body)
}
if str_starts_with(clean, "/api/memories") {
return axon_post(clean, body)
}
if str_starts_with(clean, "/api/knowledge") {
return axon_post(clean, body)
}
if str_starts_with(clean, "/api/backlog") {
return axon_post(clean, body)
}
if str_starts_with(clean, "/api/artifacts") {
return axon_post(clean, body)
}
if str_starts_with(clean, "/api/projects") {
return axon_post(clean, body)
}
if str_starts_with(clean, "/api/imprints") {
return axon_post(clean, body)
}
return err_404(clean)
}
return err_405(method, clean)
}