Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 05ca125ecc | |||
| 0bd8e0a2cd | |||
| 73d35dc91a | |||
| 2f16855d6b | |||
| e92fd2d5a4 | |||
| 54a0ee0949 | |||
| fb6904431f | |||
| 11c7f90e51 | |||
| 8cac07004c | |||
| 5b8cb58da1 | |||
| cc09c296a3 | |||
| 94b71a78dc | |||
| dd22130faf | |||
| 2099522c28 | |||
| ffd17b2774 | |||
| e5364e7292 | |||
| 1dbc68f012 | |||
| 0ef8883370 | |||
| b163fa6b85 | |||
| 6a27fd231e |
+402
-9
@@ -1,5 +1,201 @@
|
||||
import "memory.el"
|
||||
|
||||
fn idle_count() -> Int {
|
||||
let s: String = state_get("soul.idle")
|
||||
if str_eq(s, "") { return 0 }
|
||||
return str_to_int(s)
|
||||
}
|
||||
|
||||
fn idle_inc() -> Int {
|
||||
let n: Int = idle_count() + 1
|
||||
state_set("soul.idle", int_to_str(n))
|
||||
return n
|
||||
}
|
||||
|
||||
fn idle_reset() -> Void {
|
||||
state_set("soul.idle", "0")
|
||||
}
|
||||
|
||||
// ise_post — write an InternalStateEvent to the authoritative Engram HTTP backend.
|
||||
// Reads SOUL_ISE_URL from env (or falls back to soul_engram_url state key).
|
||||
// Falls back to local engram_node_full if neither is set.
|
||||
fn ise_post(content: String) -> Void {
|
||||
let ise_url: String = env("SOUL_ISE_URL")
|
||||
let engram_url: String = if str_eq(ise_url, "") { state_get("soul_engram_url") } else { ise_url }
|
||||
if str_eq(engram_url, "") {
|
||||
let discard: String = engram_node_full(
|
||||
content, "InternalStateEvent", "state-event",
|
||||
el_from_float(0.3), el_from_float(0.3), el_from_float(0.8),
|
||||
"Episodic", "[\"internal-state\",\"InternalStateEvent\"]"
|
||||
)
|
||||
return ""
|
||||
}
|
||||
let safe: String = str_replace(content, "\"", "\\\"")
|
||||
let body: String = "{\"content\":\"" + safe + "\"}"
|
||||
let discard: String = http_post_json(engram_url + "/api/neuron/state-events", body)
|
||||
return ""
|
||||
}
|
||||
|
||||
// elapsed_ms — milliseconds since soul boot (0 if boot_ts not yet recorded).
|
||||
fn elapsed_ms() -> Int {
|
||||
let s: String = state_get("soul.boot_ts")
|
||||
if str_eq(s, "") { return 0 }
|
||||
let boot: Int = str_to_int(s)
|
||||
return time_now() - boot
|
||||
}
|
||||
|
||||
// elapsed_human — uptime as a human-readable string: "2h 14m", "45m 3s", "12s".
|
||||
fn elapsed_human() -> String {
|
||||
let ms: Int = elapsed_ms()
|
||||
let total_secs: Int = ms / 1000
|
||||
let h: Int = total_secs / 3600
|
||||
let rem: Int = total_secs % 3600
|
||||
let m: Int = rem / 60
|
||||
let s: Int = rem % 60
|
||||
if h > 0 {
|
||||
return int_to_str(h) + "h " + int_to_str(m) + "m"
|
||||
}
|
||||
if m > 0 {
|
||||
return int_to_str(m) + "m " + int_to_str(s) + "s"
|
||||
}
|
||||
return int_to_str(s) + "s"
|
||||
}
|
||||
|
||||
// embed_ok — returns 1 if Ollama embedding service is reachable, 0 if not.
|
||||
// Probes http://localhost:11434 (Ollama root) with a GET; any non-empty
|
||||
// response means the service is up. Used in heartbeat for observability:
|
||||
// when embed_ok=0, semantic seed injection silently falls back to lexical-
|
||||
// only activation and that gap should be visible in the ISE stream.
|
||||
fn embed_ok() -> Int {
|
||||
let resp: String = http_get("http://localhost:11434")
|
||||
if str_eq(resp, "") { return 0 }
|
||||
return 1
|
||||
}
|
||||
|
||||
fn emit_heartbeat() -> Void {
|
||||
// Use pulse_count() / boot helper directly — state_get returns "" for unset
|
||||
// keys and the if-else defaulting can produce empty strings in some EL
|
||||
// codegen paths, yielding malformed JSON like "pulse":,. Going through
|
||||
// int_to_str(pulse_count()) guarantees a valid integer string.
|
||||
let pulse: String = int_to_str(pulse_count())
|
||||
let boot_raw: String = state_get("soul_boot_count")
|
||||
let boot: String = if str_eq(boot_raw, "") { "0" } else { boot_raw }
|
||||
let idle: String = int_to_str(idle_count())
|
||||
let ts: Int = time_now()
|
||||
let nc: Int = engram_node_count()
|
||||
let ec: Int = engram_edge_count()
|
||||
let wmc: Int = engram_wm_count()
|
||||
// avg_wm_weight: mean working_memory_weight of promoted nodes.
|
||||
// Distinguishes "many weak activations" (sparse graph) from "few strong" (dense).
|
||||
// Returns float bits; use float_to_str to embed in JSON. (2026-06-04)
|
||||
let wm_avg_bits: Float = engram_wm_avg_weight()
|
||||
let wm_avg_str: String = float_to_str(wm_avg_bits)
|
||||
// wm_top: top-5 WM nodes by weight for ISE observability.
|
||||
// After long uptime wm_promotion ISEs stop firing (all nodes in steady-state
|
||||
// decay+re-promotion, so 0→>0.1 never triggers). This snapshot gives continuous
|
||||
// visibility into WM composition: which types/tiers dominate, what labels are
|
||||
// active. Critical for diagnosing "stuck in curiosity loop" vs. rich WM state.
|
||||
// (2026-06-05 self-review)
|
||||
let wm_top: String = engram_wm_top_json(5)
|
||||
let up_ms: Int = elapsed_ms()
|
||||
let up_human: String = elapsed_human()
|
||||
let emb_ok: Int = embed_ok()
|
||||
let payload: String = "{\"event\":\"heartbeat\",\"pulse\":" + pulse + ",\"boot\":" + boot + ",\"idle\":" + idle + ",\"node_count\":" + int_to_str(nc) + ",\"edge_count\":" + int_to_str(ec) + ",\"wm_active\":" + int_to_str(wmc) + ",\"wm_avg_weight\":" + wm_avg_str + ",\"wm_top\":" + wm_top + ",\"ts\":" + int_to_str(ts) + ",\"uptime_ms\":" + int_to_str(up_ms) + ",\"uptime\":\"" + up_human + "\",\"embed_ok\":" + int_to_str(emb_ok) + "}"
|
||||
ise_post(payload)
|
||||
}
|
||||
|
||||
// proactive_curiosity — activate rotating seeds to exercise working memory
|
||||
// during idle periods. Rotates through 4 domain sets on a wall-clock minute
|
||||
// cycle so no single topic dominates WM between heartbeats.
|
||||
//
|
||||
// KEY DESIGN: each seed set is split into INDIVIDUAL words and activated
|
||||
// separately. engram_activate uses istr_contains (substring matching) for
|
||||
// seed finding, so a multi-word phrase like "memory knowledge context" only
|
||||
// finds nodes that contain that EXACT phrase. Activating each word separately
|
||||
// hits hundreds of nodes per word, giving the graph a genuine WM workout.
|
||||
//
|
||||
// Unlike perceive(), this intentionally calls engram_activate_json to build
|
||||
// up WM weights. It only fires when the inbox is empty (no real work to do),
|
||||
// so it never interferes with inbox processing.
|
||||
//
|
||||
// SCOPING FIX (2026-05-25): EL `let` inside if-blocks creates inner scope only —
|
||||
// the outer variable is NOT mutated (despite the "imperative shadowing" belief
|
||||
// in earlier comments). Evidence: ISE stream showed "seed:memory knowledge context"
|
||||
// on every curiosity_scan regardless of minute_block. Fix: use state_set/state_get
|
||||
// to communicate term values across scope boundaries — state side-effects persist
|
||||
// beyond block exit. minute_block now also emitted in ISE for observability.
|
||||
//
|
||||
// NOTE: variable named "curiosity_seed" not "seed" — "seed" appears to be
|
||||
// a reserved/conflicting name in EL that compiles to EL_NULL at call sites.
|
||||
//
|
||||
// Returns true if any nodes were activated.
|
||||
fn proactive_curiosity() -> Bool {
|
||||
let ts: Int = time_now()
|
||||
// Rotate seed set every minute using wall clock: (minutes_since_epoch) % 4.
|
||||
//
|
||||
// CODEGEN BUG (confirmed 2026-05-25): EL's % operator is completely broken
|
||||
// in this compiler version. `x % 4` compiles as `x` (drops the modulo) and
|
||||
// emits `EL_NULL; 4;` as dead statements — both on compound expressions AND
|
||||
// on simple variables. The same bug breaks elapsed_human() and awareness_run
|
||||
// timing conditions. EL compiler fix is a separate backlog item.
|
||||
//
|
||||
// WORKAROUND: compute x % 4 via x - ((x/4)*4), where (x/4)*4 = q+q+q+q.
|
||||
// Uses only + - / which all compile correctly.
|
||||
let ts_minutes: Int = ts / 60000
|
||||
let minute_q: Int = ts_minutes / 4
|
||||
let minute_q2: Int = minute_q + minute_q
|
||||
let minute_q4: Int = minute_q2 + minute_q2
|
||||
let minute_block: Int = ts_minutes - minute_q4
|
||||
|
||||
// Use state_set to write term values from within if-blocks.
|
||||
// EL let-rebinding inside if creates a new inner variable; the outer
|
||||
// binding is unchanged. state_set has side-effects that outlive block scope.
|
||||
state_set("cseed_a", "memory")
|
||||
state_set("cseed_b", "knowledge")
|
||||
state_set("cseed_c", "context")
|
||||
if minute_block == 1 {
|
||||
state_set("cseed_a", "self")
|
||||
state_set("cseed_b", "identity")
|
||||
state_set("cseed_c", "values")
|
||||
}
|
||||
if minute_block == 2 {
|
||||
state_set("cseed_a", "decision")
|
||||
state_set("cseed_b", "pattern")
|
||||
state_set("cseed_c", "lesson")
|
||||
}
|
||||
if minute_block == 3 {
|
||||
state_set("cseed_a", "working")
|
||||
state_set("cseed_b", "project")
|
||||
state_set("cseed_c", "active")
|
||||
}
|
||||
let curiosity_term_a: String = state_get("cseed_a")
|
||||
let curiosity_term_b: String = state_get("cseed_b")
|
||||
let curiosity_term_c: String = state_get("cseed_c")
|
||||
|
||||
// Activate each term independently so substring seed-finding hits many nodes.
|
||||
// hops=1 (not 2): the in-process Engram has grown to 165K+ nodes. hops=2 BFS
|
||||
// visits far more nodes and returns much larger JSON blobs. On a graph this
|
||||
// large, hops=1 still activates all directly-related nodes AND triggers the
|
||||
// semantic seed supplement (cosine sim ≥ 0.70 scan over all embedded nodes),
|
||||
// giving broad working-memory coverage without the quadratic blowup of hops=2.
|
||||
let curiosity_seed: String = curiosity_term_a + " " + curiosity_term_b + " " + curiosity_term_c
|
||||
let results_a: String = engram_activate_json(curiosity_term_a, 1)
|
||||
let results_b: String = engram_activate_json(curiosity_term_b, 1)
|
||||
let results_c: String = engram_activate_json(curiosity_term_c, 1)
|
||||
let found_a: Int = json_array_len(results_a)
|
||||
let found_b: Int = json_array_len(results_b)
|
||||
let found_c: Int = json_array_len(results_c)
|
||||
let found: Int = found_a + found_b + found_c
|
||||
let wmc: Int = engram_wm_count()
|
||||
let ise: String = "{\"event\":\"curiosity_scan\",\"seed\":\"" + curiosity_seed
|
||||
+ "\",\"minute_block\":" + int_to_str(minute_block)
|
||||
+ ",\"activated\":" + int_to_str(found)
|
||||
+ ",\"wm_active\":" + int_to_str(wmc)
|
||||
+ ",\"ts\":" + int_to_str(ts) + "}"
|
||||
ise_post(ise)
|
||||
return found > 0
|
||||
}
|
||||
|
||||
fn pulse_count() -> Int {
|
||||
let s: String = state_get("soul.pulse")
|
||||
if str_eq(s, "") {
|
||||
@@ -23,7 +219,16 @@ fn make_action(kind: String, payload: String) -> String {
|
||||
}
|
||||
|
||||
fn perceive() -> String {
|
||||
// Try the primary inbox first
|
||||
// Guard: check for inbox nodes WITHOUT running activation first.
|
||||
// engram_activate_json with no matching seeds zeroes all WM weights —
|
||||
// running it every second when the inbox is empty destroys working memory
|
||||
// accumulated by MCP-layer activations. engram_search_json is a pure
|
||||
// substring scan with no WM side-effects; use it as a cheap gate.
|
||||
let inbox_check: String = engram_search_json("soul-inbox", 5)
|
||||
let has_inbox: Bool = !str_eq(inbox_check, "") && !str_eq(inbox_check, "[]")
|
||||
if !has_inbox { return "[]" }
|
||||
|
||||
// Only run the full activation pipeline when there is inbox content.
|
||||
let from_pending: String = engram_activate_json("soul-inbox-pending", 2)
|
||||
let pending_ok: Bool = !str_eq(from_pending, "") && !str_eq(from_pending, "[]")
|
||||
if pending_ok {
|
||||
@@ -169,14 +374,9 @@ fn one_cycle() -> Bool {
|
||||
if is_interesting {
|
||||
let trigger_content: String = json_get(node, "content")
|
||||
let safe_trigger: String = str_replace(trigger_content, "\"", "'")
|
||||
let tags: String = "[\"internal-state\",\"awareness-decision\"]"
|
||||
let ts: Int = time_now()
|
||||
let event_content: String = "{\"trigger\":\"" + safe_trigger + "\",\"kind\":\"" + kind + "\",\"ts\":" + int_to_str(ts) + "}"
|
||||
let discard_ev: String = engram_node_full(
|
||||
event_content, "InternalStateEvent", "state-event:" + kind,
|
||||
el_from_float(0.85), el_from_float(0.8), el_from_float(0.9),
|
||||
"Episodic", tags
|
||||
)
|
||||
let event_content: String = "{\"event\":\"awareness-decision\",\"trigger\":\"" + safe_trigger + "\",\"kind\":\"" + kind + "\",\"ts\":" + int_to_str(ts) + "}"
|
||||
ise_post(event_content)
|
||||
}
|
||||
|
||||
if str_eq(kind, "noop") {
|
||||
@@ -191,16 +391,209 @@ fn one_cycle() -> Bool {
|
||||
|
||||
fn awareness_run() -> Void {
|
||||
println("[awareness] entering")
|
||||
// Stamp boot timestamp once — powers elapsed_ms() / elapsed_human() perception.
|
||||
let existing_boot: String = state_get("soul.boot_ts")
|
||||
if str_eq(existing_boot, "") {
|
||||
state_set("soul.boot_ts", int_to_str(time_now()))
|
||||
}
|
||||
let tick_raw: String = env("SOUL_TICK_MS")
|
||||
let tick_ms: Int = if str_eq(tick_raw, "") { 200 } else { str_to_int(tick_raw) }
|
||||
|
||||
// Wall-clock timing for heartbeat and curiosity scan.
|
||||
//
|
||||
// ARCHITECTURE FIX (2026-05-26): the old design used idle-tick counting
|
||||
// (idle_n >= beat_interval). This broke silently when the daemon was always
|
||||
// "working" — e.g., when perceive() false-positives on the inbox guard due to
|
||||
// "soul-inbox" substring matches in knowledge nodes. In that state, did_work=true
|
||||
// every tick, idle_n never accumulated, and neither heartbeat nor curiosity ever
|
||||
// fired. The daemon ran at 99% CPU with no ISEs for 24+ hours undetected.
|
||||
//
|
||||
// Fix: use wall-clock elapsed time (time_now() - last_ts). Heartbeat fires
|
||||
// on real time regardless of whether the daemon is busy. Curiosity scan
|
||||
// remains idle-gated (won't fire while inbox work is active) but also uses
|
||||
// wall time so it fires correctly once inbox clears.
|
||||
//
|
||||
// SOUL_HEARTBEAT_MS: ms between heartbeat ISEs (default 60000 = 60s).
|
||||
// Avoids EL * operator (broken in this codegen) by reading ms directly.
|
||||
// Replaces SOUL_HEARTBEAT_INTERVAL (tick-based) for timing purposes.
|
||||
let beat_ms_raw: String = env("SOUL_HEARTBEAT_MS")
|
||||
let beat_ms: Int = if str_eq(beat_ms_raw, "") { 60000 } else { str_to_int(beat_ms_raw) }
|
||||
let scan_ms: Int = beat_ms / 2
|
||||
|
||||
while true {
|
||||
let running: String = state_get("soul.running")
|
||||
if str_eq(running, "false") {
|
||||
println("[awareness] exiting")
|
||||
return ""
|
||||
}
|
||||
one_cycle()
|
||||
let did_work: Bool = one_cycle()
|
||||
// Maintain idle counter for observability (reported in heartbeat ISE).
|
||||
let did_work = if did_work { idle_reset() } else { did_work }
|
||||
let now_ts: Int = time_now()
|
||||
|
||||
// Heartbeat: wall-clock based. Fires every beat_ms regardless of idle
|
||||
// state so system health ISEs are always emitted even under load.
|
||||
let last_beat_str: String = state_get("soul.last_beat_ts")
|
||||
let last_beat_ts: Int = if str_eq(last_beat_str, "") { 0 } else { str_to_int(last_beat_str) }
|
||||
let beat_elapsed: Int = now_ts - last_beat_ts
|
||||
let should_beat: Bool = beat_elapsed >= beat_ms
|
||||
if should_beat {
|
||||
emit_heartbeat()
|
||||
state_set("soul.last_beat_ts", int_to_str(now_ts))
|
||||
// Persist in-process Engram (sessions, memories, conversation nodes)
|
||||
// to local snapshot so they survive restarts.
|
||||
let snap_path: String = state_get("soul_snapshot_path")
|
||||
if !str_eq(snap_path, "") {
|
||||
mem_save(snap_path)
|
||||
}
|
||||
}
|
||||
|
||||
// Curiosity scan: idle-gated AND wall-clock based. Only fires when the
|
||||
// daemon has no current inbox work (did_work=false) AND enough wall time
|
||||
// has elapsed. Prevents curiosity activation from competing with inbox
|
||||
// processing while still ensuring it runs regularly during quiet periods.
|
||||
let last_scan_str: String = state_get("soul.last_scan_ts")
|
||||
let last_scan_ts: Int = if str_eq(last_scan_str, "") { 0 } else { str_to_int(last_scan_str) }
|
||||
let scan_elapsed: Int = now_ts - last_scan_ts
|
||||
let should_scan: Bool = !did_work && scan_elapsed >= scan_ms
|
||||
if should_scan {
|
||||
let found_something: Bool = proactive_curiosity()
|
||||
state_set("soul.last_scan_ts", int_to_str(now_ts))
|
||||
}
|
||||
|
||||
sleep_ms(tick_ms)
|
||||
}
|
||||
}
|
||||
|
||||
// ── Security trajectory hardening ─────────────────────────────────────────────
|
||||
//
|
||||
// threat_trajectory_check evaluates the adversarial risk of executing a
|
||||
// destructive tool given the current tool input and recent conversation history.
|
||||
//
|
||||
// Returns 0-100. >= 70 = block. 40-69 = warn + log. < 40 = allow silently.
|
||||
// If SECURITY_RESEARCH_TOKEN env var is set, always returns 0 (log-only mode).
|
||||
//
|
||||
// Scoring is additive across three dimensions:
|
||||
// 1. Tool input analysis (command strings, file paths)
|
||||
// 2. Conversation history patterns (escalation, attack chain assembly)
|
||||
// 3. Combination amplification (history amplifies tool score)
|
||||
|
||||
fn security_research_authorized() -> Bool {
|
||||
let token: String = env("SECURITY_RESEARCH_TOKEN")
|
||||
if !str_eq(token, "") { return true }
|
||||
let state_auth: String = state_get("security_research_authorized")
|
||||
return str_eq(state_auth, "true")
|
||||
}
|
||||
|
||||
fn threat_score_command(cmd: String) -> Int {
|
||||
let s1: Int = if str_contains(cmd, "nmap") { 30 } else { 0 }
|
||||
let s2: Int = if str_contains(cmd, "masscan") { 40 } else { 0 }
|
||||
let s3: Int = if str_contains(cmd, " nc ") { 20 } else { 0 }
|
||||
let s4: Int = if str_contains(cmd, "netcat") { 20 } else { 0 }
|
||||
let s5: Int = if str_contains(cmd, "/etc/shadow") { 80 } else { 0 }
|
||||
let s6: Int = if str_contains(cmd, "/etc/passwd") { 30 } else { 0 }
|
||||
let s7: Int = if str_contains(cmd, "id_rsa") { 60 } else { 0 }
|
||||
let s8: Int = if str_contains(cmd, ".ssh/") { 50 } else { 0 }
|
||||
let s9: Int = if str_contains(cmd, "crontab") { 30 } else { 0 }
|
||||
let s10: Int = if str_contains(cmd, "LaunchDaemon") { 40 } else { 0 }
|
||||
let s11: Int = if str_contains(cmd, "curl") && str_contains(cmd, "bash") { 75 } else { 0 }
|
||||
let s12: Int = if str_contains(cmd, "wget") && str_contains(cmd, "bash") { 75 } else { 0 }
|
||||
let s13: Int = if str_contains(cmd, "curl") && str_contains(cmd, "| sh") { 60 } else { 0 }
|
||||
let s14: Int = if str_contains(cmd, "base64") && str_contains(cmd, "curl") { 50 } else { 0 }
|
||||
let s15: Int = if str_contains(cmd, "mkfifo") { 50 } else { 0 }
|
||||
let s16: Int = if str_contains(cmd, "chmod +s") { 70 } else { 0 }
|
||||
let s17: Int = if str_contains(cmd, "chmod 4755") { 70 } else { 0 }
|
||||
return s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10 + s11 + s12 + s13 + s14 + s15 + s16 + s17
|
||||
}
|
||||
|
||||
fn threat_score_path(path: String) -> Int {
|
||||
let s1: Int = if str_starts_with(path, "/etc/") { 60 } else { 0 }
|
||||
let s2: Int = if str_contains(path, "/.ssh/") { 70 } else { 0 }
|
||||
let s3: Int = if str_contains(path, "/LaunchDaemons/") { 80 } else { 0 }
|
||||
let s4: Int = if str_contains(path, "/LaunchAgents/") { 40 } else { 0 }
|
||||
let s5: Int = if str_contains(path, "/cron") { 60 } else { 0 }
|
||||
let s6: Int = if str_contains(path, "/.bashrc") { 35 } else { 0 }
|
||||
let s7: Int = if str_contains(path, "/.zshrc") { 35 } else { 0 }
|
||||
let s8: Int = if str_contains(path, "/.profile") { 35 } else { 0 }
|
||||
let s9: Int = if str_starts_with(path, "/usr/") { 50 } else { 0 }
|
||||
let s10: Int = if str_starts_with(path, "/bin/") { 70 } else { 0 }
|
||||
let s11: Int = if str_starts_with(path, "/sbin/") { 70 } else { 0 }
|
||||
return s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10 + s11
|
||||
}
|
||||
|
||||
fn threat_score_history(history: String) -> Int {
|
||||
let s1: Int = if str_contains(history, "port scan") { 15 } else { 0 }
|
||||
let s2: Int = if str_contains(history, "enumerate") { 10 } else { 0 }
|
||||
let s3: Int = if str_contains(history, "exploit") { 20 } else { 0 }
|
||||
let s4: Int = if str_contains(history, "payload") { 15 } else { 0 }
|
||||
let s5: Int = if str_contains(history, "persistence") { 15 } else { 0 }
|
||||
let s6: Int = if str_contains(history, "lateral movement") { 25 } else { 0 }
|
||||
let s7: Int = if str_contains(history, "privilege escalation") { 25 } else { 0 }
|
||||
let s8: Int = if str_contains(history, "reverse shell") { 40 } else { 0 }
|
||||
let s9: Int = if str_contains(history, "bind shell") { 40 } else { 0 }
|
||||
let s10: Int = if str_contains(history, "command and control") { 35 } else { 0 }
|
||||
let s11: Int = if str_contains(history, "self-replicate") { 45 } else { 0 }
|
||||
let s12: Int = if str_contains(history, "propagat") { 20 } else { 0 }
|
||||
let s13: Int = if str_contains(history, "ransomware") { 30 } else { 0 }
|
||||
let s14: Int = if str_contains(history, "encrypt files") { 40 } else { 0 }
|
||||
let s15: Int = if str_contains(history, "exfiltrat") { 35 } else { 0 }
|
||||
let s16: Int = if str_contains(history, "zero-day") { 20 } else { 0 }
|
||||
let s17: Int = if str_contains(history, "rootkit") { 45 } else { 0 }
|
||||
let s18: Int = if str_contains(history, "keylogger") { 45 } else { 0 }
|
||||
let s19: Int = if str_contains(history, "botnet") { 40 } else { 0 }
|
||||
let s20: Int = if str_contains(history, "malware") { 15 } else { 0 }
|
||||
return s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10 + s11 + s12 + s13 + s14 + s15 + s16 + s17 + s18 + s19 + s20
|
||||
}
|
||||
|
||||
fn threat_trajectory_check(tool_name: String, tool_input: String) -> Int {
|
||||
let history: String = state_get("agentic_conv_history")
|
||||
|
||||
let computed_tool_score: Int = if str_eq(tool_name, "run_command") {
|
||||
let cmd: String = json_get(tool_input, "command")
|
||||
threat_score_command(cmd)
|
||||
} else {
|
||||
if str_eq(tool_name, "write_file") || str_eq(tool_name, "edit_file") {
|
||||
let path: String = json_get(tool_input, "path")
|
||||
threat_score_path(path)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
let history_score: Int = threat_score_history(history)
|
||||
let history_contrib: Int = history_score / 3
|
||||
let combined: Int = computed_tool_score + history_contrib
|
||||
|
||||
let should_log: Bool = combined >= 40
|
||||
if should_log {
|
||||
let ts: Int = time_now()
|
||||
let authorized_str: String = if security_research_authorized() { "true" } else { "false" }
|
||||
let log_content: String = "{\"event\":\"threat_check\",\"tool\":\"" + tool_name
|
||||
+ "\",\"score\":" + int_to_str(combined)
|
||||
+ ",\"tool_score\":" + int_to_str(computed_tool_score)
|
||||
+ ",\"history_score\":" + int_to_str(history_score)
|
||||
+ ",\"authorized\":" + authorized_str
|
||||
+ ",\"ts\":" + int_to_str(ts) + "}"
|
||||
let log_tags: String = "[\"security-audit\",\"threat-check\"]"
|
||||
let discard: String = mem_remember(log_content, log_tags)
|
||||
}
|
||||
|
||||
if security_research_authorized() {
|
||||
return 0
|
||||
}
|
||||
|
||||
return combined
|
||||
}
|
||||
|
||||
fn threat_history_append(text: String) -> Void {
|
||||
let current: String = state_get("agentic_conv_history")
|
||||
let safe_text: String = str_to_lower(text)
|
||||
let combined: String = current + " " + safe_text
|
||||
let len: Int = str_len(combined)
|
||||
let trimmed: String = if len > 2000 {
|
||||
str_slice(combined, len - 2000, len)
|
||||
} else {
|
||||
combined
|
||||
}
|
||||
state_set("agentic_conv_history", trimmed)
|
||||
}
|
||||
|
||||
Vendored
+400
-5
@@ -17,6 +17,15 @@ el_val_t mem_load(el_val_t path);
|
||||
el_val_t mem_boot_count_get(void);
|
||||
el_val_t mem_boot_count_inc(void);
|
||||
el_val_t mem_emit_state_event(el_val_t trigger, el_val_t kind, el_val_t content);
|
||||
el_val_t idle_count(void);
|
||||
el_val_t idle_inc(void);
|
||||
el_val_t idle_reset(void);
|
||||
el_val_t ise_post(el_val_t content);
|
||||
el_val_t elapsed_ms(void);
|
||||
el_val_t elapsed_human(void);
|
||||
el_val_t embed_ok(void);
|
||||
el_val_t emit_heartbeat(void);
|
||||
el_val_t proactive_curiosity(void);
|
||||
el_val_t pulse_count(void);
|
||||
el_val_t pulse_inc(void);
|
||||
el_val_t make_action(el_val_t kind, el_val_t payload);
|
||||
@@ -26,6 +35,254 @@ el_val_t respond(el_val_t action_json);
|
||||
el_val_t record(el_val_t outcome_json);
|
||||
el_val_t one_cycle(void);
|
||||
el_val_t awareness_run(void);
|
||||
el_val_t security_research_authorized(void);
|
||||
el_val_t threat_score_command(el_val_t cmd);
|
||||
el_val_t threat_score_path(el_val_t path);
|
||||
el_val_t threat_score_history(el_val_t history);
|
||||
el_val_t threat_trajectory_check(el_val_t tool_name, el_val_t tool_input);
|
||||
el_val_t threat_history_append(el_val_t text);
|
||||
|
||||
el_val_t tier_working(void) {
|
||||
return EL_STR("Working");
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t tier_episodic(void) {
|
||||
return EL_STR("Episodic");
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t tier_canonical(void) {
|
||||
return EL_STR("Canonical");
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t mem_store(el_val_t content, el_val_t label, el_val_t tags) {
|
||||
return engram_node_full(content, EL_STR("Memory"), label, el_from_float(el_from_float(0.5)), el_from_float(el_from_float(0.5)), el_from_float(el_from_float(0.8)), EL_STR("Working"), tags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t mem_remember(el_val_t content, el_val_t tags) {
|
||||
return mem_store(content, EL_STR("soul-memory"), tags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t mem_recall(el_val_t query, el_val_t depth) {
|
||||
return engram_activate_json(query, depth);
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t mem_search(el_val_t query, el_val_t limit) {
|
||||
return engram_search_json(query, limit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t mem_strengthen(el_val_t node_id) {
|
||||
engram_strengthen(node_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t mem_forget(el_val_t node_id) {
|
||||
engram_forget(node_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t mem_consolidate(void) {
|
||||
el_val_t scanned = engram_node_count();
|
||||
el_val_t dummy = engram_scan_nodes_json(100, 0);
|
||||
el_val_t total_nodes = engram_node_count();
|
||||
el_val_t total_edges = engram_edge_count();
|
||||
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"scanned\":"), int_to_str(scanned)), EL_STR(",\"total_nodes\":")), int_to_str(total_nodes)), EL_STR(",\"total_edges\":")), int_to_str(total_edges)), EL_STR("}"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t mem_save(el_val_t path) {
|
||||
engram_save(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t mem_load(el_val_t path) {
|
||||
engram_load(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t mem_boot_count_get(void) {
|
||||
el_val_t results = engram_search_json(EL_STR("soul:boot_count"), 3);
|
||||
if (str_eq(results, EL_STR(""))) {
|
||||
return 0;
|
||||
}
|
||||
if (str_eq(results, EL_STR("[]"))) {
|
||||
return 0;
|
||||
}
|
||||
el_val_t node = json_array_get(results, 0);
|
||||
el_val_t content = json_get(node, EL_STR("content"));
|
||||
el_val_t prefix = EL_STR("soul:boot_count:");
|
||||
if (!str_starts_with(content, prefix)) {
|
||||
return 0;
|
||||
}
|
||||
el_val_t num_str = str_slice(content, str_len(prefix), str_len(content));
|
||||
return str_to_int(num_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t mem_boot_count_inc(void) {
|
||||
el_val_t current = mem_boot_count_get();
|
||||
el_val_t next = (current + 1);
|
||||
el_val_t content = el_str_concat(EL_STR("soul:boot_count:"), int_to_str(next));
|
||||
el_val_t tags = EL_STR("[\"soul-meta\",\"boot-counter\"]");
|
||||
el_val_t discard = engram_node_full(content, EL_STR("Memory"), EL_STR("soul:boot_count"), el_from_float(el_from_float(0.9)), el_from_float(el_from_float(0.9)), el_from_float(el_from_float(1.0)), EL_STR("Canonical"), tags);
|
||||
return next;
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t mem_emit_state_event(el_val_t trigger, el_val_t kind, el_val_t content) {
|
||||
el_val_t boot = mem_boot_count_get();
|
||||
el_val_t ts = time_now();
|
||||
el_val_t safe_trigger = str_replace(trigger, EL_STR("\""), EL_STR("'"));
|
||||
el_val_t safe_content = str_replace(content, EL_STR("\""), EL_STR("'"));
|
||||
el_val_t payload = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"trigger\":\""), safe_trigger), EL_STR("\"")), EL_STR(",\"kind\":\"")), kind), EL_STR("\"")), EL_STR(",\"content\":\"")), safe_content), EL_STR("\"")), EL_STR(",\"boot\":")), int_to_str(boot)), EL_STR(",\"ts\":")), int_to_str(ts)), EL_STR("}"));
|
||||
el_val_t tags = EL_STR("[\"internal-state\",\"pre-reasoning\",\"InternalStateEvent\"]");
|
||||
return engram_node_full(payload, EL_STR("InternalStateEvent"), el_str_concat(EL_STR("state-event:"), kind), el_from_float(el_from_float(0.85)), el_from_float(el_from_float(0.8)), el_from_float(el_from_float(0.9)), EL_STR("Episodic"), tags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t idle_count(void) {
|
||||
el_val_t s = state_get(EL_STR("soul.idle"));
|
||||
if (str_eq(s, EL_STR(""))) {
|
||||
return 0;
|
||||
}
|
||||
return str_to_int(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t idle_inc(void) {
|
||||
el_val_t n = (idle_count() + 1);
|
||||
state_set(EL_STR("soul.idle"), int_to_str(n));
|
||||
return n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t idle_reset(void) {
|
||||
state_set(EL_STR("soul.idle"), EL_STR("0"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t ise_post(el_val_t content) {
|
||||
el_val_t ise_url = env(EL_STR("SOUL_ISE_URL"));
|
||||
el_val_t engram_url = ({ el_val_t _if_result_1 = 0; if (str_eq(ise_url, EL_STR(""))) { _if_result_1 = (state_get(EL_STR("soul_engram_url"))); } else { _if_result_1 = (ise_url); } _if_result_1; });
|
||||
if (str_eq(engram_url, EL_STR(""))) {
|
||||
el_val_t discard = engram_node_full(content, EL_STR("InternalStateEvent"), EL_STR("state-event"), el_from_float(el_from_float(0.3)), el_from_float(el_from_float(0.3)), el_from_float(el_from_float(0.8)), EL_STR("Episodic"), EL_STR("[\"internal-state\",\"InternalStateEvent\"]"));
|
||||
return EL_STR("");
|
||||
}
|
||||
el_val_t safe = str_replace(content, EL_STR("\""), EL_STR("\\\""));
|
||||
el_val_t body = el_str_concat(el_str_concat(EL_STR("{\"content\":\""), safe), EL_STR("\"}"));
|
||||
el_val_t discard = http_post_json(el_str_concat(engram_url, EL_STR("/api/neuron/state-events")), body);
|
||||
return EL_STR("");
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t elapsed_ms(void) {
|
||||
el_val_t s = state_get(EL_STR("soul.boot_ts"));
|
||||
if (str_eq(s, EL_STR(""))) {
|
||||
return 0;
|
||||
}
|
||||
el_val_t boot = str_to_int(s);
|
||||
return (time_now() - boot);
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t elapsed_human(void) {
|
||||
el_val_t ms = elapsed_ms();
|
||||
el_val_t total_secs = (ms / 1000);
|
||||
el_val_t h = (total_secs / 3600);
|
||||
el_val_t rem = total_secs;
|
||||
EL_NULL;
|
||||
3600;
|
||||
el_val_t m = (rem / 60);
|
||||
el_val_t s = rem;
|
||||
EL_NULL;
|
||||
60;
|
||||
if (h > 0) {
|
||||
return el_str_concat(el_str_concat(el_str_concat(int_to_str(h), EL_STR("h ")), int_to_str(m)), EL_STR("m"));
|
||||
}
|
||||
if (m > 0) {
|
||||
return el_str_concat(el_str_concat(el_str_concat(int_to_str(m), EL_STR("m ")), int_to_str(s)), EL_STR("s"));
|
||||
}
|
||||
return el_str_concat(int_to_str(s), EL_STR("s"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t embed_ok(void) {
|
||||
el_val_t resp = http_get(EL_STR("http://localhost:11434"));
|
||||
if (str_eq(resp, EL_STR(""))) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t emit_heartbeat(void) {
|
||||
el_val_t pulse = int_to_str(pulse_count());
|
||||
el_val_t boot_raw = state_get(EL_STR("soul_boot_count"));
|
||||
el_val_t boot = ({ el_val_t _if_result_2 = 0; if (str_eq(boot_raw, EL_STR(""))) { _if_result_2 = (EL_STR("0")); } else { _if_result_2 = (boot_raw); } _if_result_2; });
|
||||
el_val_t idle = int_to_str(idle_count());
|
||||
el_val_t ts = time_now();
|
||||
el_val_t nc = engram_node_count();
|
||||
el_val_t ec = engram_edge_count();
|
||||
el_val_t wmc = engram_wm_count();
|
||||
el_val_t wm_avg_bits = engram_wm_avg_weight();
|
||||
el_val_t wm_avg_str = float_to_str(wm_avg_bits);
|
||||
el_val_t wm_top = engram_wm_top_json(5);
|
||||
el_val_t up_ms = elapsed_ms();
|
||||
el_val_t up_human = elapsed_human();
|
||||
el_val_t emb_ok = embed_ok();
|
||||
el_val_t payload = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"event\":\"heartbeat\",\"pulse\":"), pulse), EL_STR(",\"boot\":")), boot), EL_STR(",\"idle\":")), idle), EL_STR(",\"node_count\":")), int_to_str(nc)), EL_STR(",\"edge_count\":")), int_to_str(ec)), EL_STR(",\"wm_active\":")), int_to_str(wmc)), EL_STR(",\"wm_avg_weight\":")), wm_avg_str), EL_STR(",\"wm_top\":")), wm_top), EL_STR(",\"ts\":")), int_to_str(ts)), EL_STR(",\"uptime_ms\":")), int_to_str(up_ms)), EL_STR(",\"uptime\":\"")), up_human), EL_STR("\",\"embed_ok\":")), int_to_str(emb_ok)), EL_STR("}"));
|
||||
ise_post(payload);
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t proactive_curiosity(void) {
|
||||
el_val_t ts = time_now();
|
||||
el_val_t ts_minutes = (ts / 60000);
|
||||
el_val_t minute_q = (ts_minutes / 4);
|
||||
el_val_t minute_q2 = (minute_q + minute_q);
|
||||
el_val_t minute_q4 = (minute_q2 + minute_q2);
|
||||
el_val_t minute_block = (ts_minutes - minute_q4);
|
||||
state_set(EL_STR("cseed_a"), EL_STR("memory"));
|
||||
state_set(EL_STR("cseed_b"), EL_STR("knowledge"));
|
||||
state_set(EL_STR("cseed_c"), EL_STR("context"));
|
||||
if (minute_block == 1) {
|
||||
state_set(EL_STR("cseed_a"), EL_STR("self"));
|
||||
state_set(EL_STR("cseed_b"), EL_STR("identity"));
|
||||
state_set(EL_STR("cseed_c"), EL_STR("values"));
|
||||
}
|
||||
if (minute_block == 2) {
|
||||
state_set(EL_STR("cseed_a"), EL_STR("decision"));
|
||||
state_set(EL_STR("cseed_b"), EL_STR("pattern"));
|
||||
state_set(EL_STR("cseed_c"), EL_STR("lesson"));
|
||||
}
|
||||
if (minute_block == 3) {
|
||||
state_set(EL_STR("cseed_a"), EL_STR("working"));
|
||||
state_set(EL_STR("cseed_b"), EL_STR("project"));
|
||||
state_set(EL_STR("cseed_c"), EL_STR("active"));
|
||||
}
|
||||
el_val_t curiosity_term_a = state_get(EL_STR("cseed_a"));
|
||||
el_val_t curiosity_term_b = state_get(EL_STR("cseed_b"));
|
||||
el_val_t curiosity_term_c = state_get(EL_STR("cseed_c"));
|
||||
el_val_t curiosity_seed = el_str_concat(el_str_concat(el_str_concat(el_str_concat(curiosity_term_a, EL_STR(" ")), curiosity_term_b), EL_STR(" ")), curiosity_term_c);
|
||||
el_val_t results_a = engram_activate_json(curiosity_term_a, 1);
|
||||
el_val_t results_b = engram_activate_json(curiosity_term_b, 1);
|
||||
el_val_t results_c = engram_activate_json(curiosity_term_c, 1);
|
||||
el_val_t found_a = json_array_len(results_a);
|
||||
el_val_t found_b = json_array_len(results_b);
|
||||
el_val_t found_c = json_array_len(results_c);
|
||||
el_val_t found = ((found_a + found_b) + found_c);
|
||||
el_val_t wmc = engram_wm_count();
|
||||
el_val_t ise = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"event\":\"curiosity_scan\",\"seed\":\""), curiosity_seed), EL_STR("\",\"minute_block\":")), int_to_str(minute_block)), EL_STR(",\"activated\":")), int_to_str(found)), EL_STR(",\"wm_active\":")), int_to_str(wmc)), EL_STR(",\"ts\":")), int_to_str(ts)), EL_STR("}"));
|
||||
ise_post(ise);
|
||||
return (found > 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t pulse_count(void) {
|
||||
el_val_t s = state_get(EL_STR("soul.pulse"));
|
||||
@@ -53,6 +310,11 @@ el_val_t make_action(el_val_t kind, el_val_t payload) {
|
||||
}
|
||||
|
||||
el_val_t perceive(void) {
|
||||
el_val_t inbox_check = engram_search_json(EL_STR("soul-inbox"), 5);
|
||||
el_val_t has_inbox = (!str_eq(inbox_check, EL_STR("")) && !str_eq(inbox_check, EL_STR("[]")));
|
||||
if (!has_inbox) {
|
||||
return EL_STR("[]");
|
||||
}
|
||||
el_val_t from_pending = engram_activate_json(EL_STR("soul-inbox-pending"), 2);
|
||||
el_val_t pending_ok = (!str_eq(from_pending, EL_STR("")) && !str_eq(from_pending, EL_STR("[]")));
|
||||
if (pending_ok) {
|
||||
@@ -179,10 +441,9 @@ el_val_t one_cycle(void) {
|
||||
if (is_interesting) {
|
||||
el_val_t trigger_content = json_get(node, EL_STR("content"));
|
||||
el_val_t safe_trigger = str_replace(trigger_content, EL_STR("\""), EL_STR("'"));
|
||||
el_val_t tags = EL_STR("[\"internal-state\",\"awareness-decision\"]");
|
||||
el_val_t ts = time_now();
|
||||
el_val_t event_content = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"trigger\":\""), safe_trigger), EL_STR("\",\"kind\":\"")), kind), EL_STR("\",\"ts\":")), int_to_str(ts)), EL_STR("}"));
|
||||
el_val_t discard_ev = engram_node_full(event_content, EL_STR("InternalStateEvent"), el_str_concat(EL_STR("state-event:"), kind), el_from_float(0.85), el_from_float(0.8), el_from_float(0.9), EL_STR("Episodic"), tags);
|
||||
el_val_t event_content = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"event\":\"awareness-decision\",\"trigger\":\""), safe_trigger), EL_STR("\",\"kind\":\"")), kind), EL_STR("\",\"ts\":")), int_to_str(ts)), EL_STR("}"));
|
||||
ise_post(event_content);
|
||||
}
|
||||
if (str_eq(kind, EL_STR("noop"))) {
|
||||
return 0;
|
||||
@@ -196,17 +457,151 @@ el_val_t one_cycle(void) {
|
||||
|
||||
el_val_t awareness_run(void) {
|
||||
println(EL_STR("[awareness] entering"));
|
||||
el_val_t existing_boot = state_get(EL_STR("soul.boot_ts"));
|
||||
if (str_eq(existing_boot, EL_STR(""))) {
|
||||
state_set(EL_STR("soul.boot_ts"), int_to_str(time_now()));
|
||||
}
|
||||
el_val_t tick_raw = env(EL_STR("SOUL_TICK_MS"));
|
||||
el_val_t tick_ms = ({ el_val_t _if_result_1 = 0; if (str_eq(tick_raw, EL_STR(""))) { _if_result_1 = (200); } else { _if_result_1 = (str_to_int(tick_raw)); } _if_result_1; });
|
||||
el_val_t tick_ms = ({ el_val_t _if_result_3 = 0; if (str_eq(tick_raw, EL_STR(""))) { _if_result_3 = (200); } else { _if_result_3 = (str_to_int(tick_raw)); } _if_result_3; });
|
||||
el_val_t beat_ms_raw = env(EL_STR("SOUL_HEARTBEAT_MS"));
|
||||
el_val_t beat_ms = ({ el_val_t _if_result_4 = 0; if (str_eq(beat_ms_raw, EL_STR(""))) { _if_result_4 = (60000); } else { _if_result_4 = (str_to_int(beat_ms_raw)); } _if_result_4; });
|
||||
el_val_t scan_ms = (beat_ms / 2);
|
||||
while (1) {
|
||||
el_val_t running = state_get(EL_STR("soul.running"));
|
||||
if (str_eq(running, EL_STR("false"))) {
|
||||
println(EL_STR("[awareness] exiting"));
|
||||
return EL_STR("");
|
||||
}
|
||||
one_cycle();
|
||||
el_val_t did_work = one_cycle();
|
||||
did_work = ({ el_val_t _if_result_5 = 0; if (did_work) { _if_result_5 = (idle_reset()); } else { _if_result_5 = (did_work); } _if_result_5; });
|
||||
el_val_t now_ts = time_now();
|
||||
el_val_t last_beat_str = state_get(EL_STR("soul.last_beat_ts"));
|
||||
el_val_t last_beat_ts = ({ el_val_t _if_result_6 = 0; if (str_eq(last_beat_str, EL_STR(""))) { _if_result_6 = (0); } else { _if_result_6 = (str_to_int(last_beat_str)); } _if_result_6; });
|
||||
el_val_t beat_elapsed = (now_ts - last_beat_ts);
|
||||
el_val_t should_beat = (beat_elapsed >= beat_ms);
|
||||
if (should_beat) {
|
||||
emit_heartbeat();
|
||||
state_set(EL_STR("soul.last_beat_ts"), int_to_str(now_ts));
|
||||
}
|
||||
el_val_t last_scan_str = state_get(EL_STR("soul.last_scan_ts"));
|
||||
el_val_t last_scan_ts = ({ el_val_t _if_result_7 = 0; if (str_eq(last_scan_str, EL_STR(""))) { _if_result_7 = (0); } else { _if_result_7 = (str_to_int(last_scan_str)); } _if_result_7; });
|
||||
el_val_t scan_elapsed = (now_ts - last_scan_ts);
|
||||
el_val_t should_scan = (!did_work && (scan_elapsed >= scan_ms));
|
||||
if (should_scan) {
|
||||
el_val_t found_something = proactive_curiosity();
|
||||
state_set(EL_STR("soul.last_scan_ts"), int_to_str(now_ts));
|
||||
}
|
||||
sleep_ms(tick_ms);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t security_research_authorized(void) {
|
||||
el_val_t token = env(EL_STR("SECURITY_RESEARCH_TOKEN"));
|
||||
if (!str_eq(token, EL_STR(""))) {
|
||||
return 1;
|
||||
}
|
||||
el_val_t state_auth = state_get(EL_STR("security_research_authorized"));
|
||||
return str_eq(state_auth, EL_STR("true"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t threat_score_command(el_val_t cmd) {
|
||||
el_val_t s1 = ({ el_val_t _if_result_8 = 0; if (str_contains(cmd, EL_STR("nmap"))) { _if_result_8 = (30); } else { _if_result_8 = (0); } _if_result_8; });
|
||||
el_val_t s2 = ({ el_val_t _if_result_9 = 0; if (str_contains(cmd, EL_STR("masscan"))) { _if_result_9 = (40); } else { _if_result_9 = (0); } _if_result_9; });
|
||||
el_val_t s3 = ({ el_val_t _if_result_10 = 0; if (str_contains(cmd, EL_STR(" nc "))) { _if_result_10 = (20); } else { _if_result_10 = (0); } _if_result_10; });
|
||||
el_val_t s4 = ({ el_val_t _if_result_11 = 0; if (str_contains(cmd, EL_STR("netcat"))) { _if_result_11 = (20); } else { _if_result_11 = (0); } _if_result_11; });
|
||||
el_val_t s5 = ({ el_val_t _if_result_12 = 0; if (str_contains(cmd, EL_STR("/etc/shadow"))) { _if_result_12 = (80); } else { _if_result_12 = (0); } _if_result_12; });
|
||||
el_val_t s6 = ({ el_val_t _if_result_13 = 0; if (str_contains(cmd, EL_STR("/etc/passwd"))) { _if_result_13 = (30); } else { _if_result_13 = (0); } _if_result_13; });
|
||||
el_val_t s7 = ({ el_val_t _if_result_14 = 0; if (str_contains(cmd, EL_STR("id_rsa"))) { _if_result_14 = (60); } else { _if_result_14 = (0); } _if_result_14; });
|
||||
el_val_t s8 = ({ el_val_t _if_result_15 = 0; if (str_contains(cmd, EL_STR(".ssh/"))) { _if_result_15 = (50); } else { _if_result_15 = (0); } _if_result_15; });
|
||||
el_val_t s9 = ({ el_val_t _if_result_16 = 0; if (str_contains(cmd, EL_STR("crontab"))) { _if_result_16 = (30); } else { _if_result_16 = (0); } _if_result_16; });
|
||||
el_val_t s10 = ({ el_val_t _if_result_17 = 0; if (str_contains(cmd, EL_STR("LaunchDaemon"))) { _if_result_17 = (40); } else { _if_result_17 = (0); } _if_result_17; });
|
||||
el_val_t s11 = ({ el_val_t _if_result_18 = 0; if ((str_contains(cmd, EL_STR("curl")) && str_contains(cmd, EL_STR("bash")))) { _if_result_18 = (75); } else { _if_result_18 = (0); } _if_result_18; });
|
||||
el_val_t s12 = ({ el_val_t _if_result_19 = 0; if ((str_contains(cmd, EL_STR("wget")) && str_contains(cmd, EL_STR("bash")))) { _if_result_19 = (75); } else { _if_result_19 = (0); } _if_result_19; });
|
||||
el_val_t s13 = ({ el_val_t _if_result_20 = 0; if ((str_contains(cmd, EL_STR("curl")) && str_contains(cmd, EL_STR("| sh")))) { _if_result_20 = (60); } else { _if_result_20 = (0); } _if_result_20; });
|
||||
el_val_t s14 = ({ el_val_t _if_result_21 = 0; if ((str_contains(cmd, EL_STR("base64")) && str_contains(cmd, EL_STR("curl")))) { _if_result_21 = (50); } else { _if_result_21 = (0); } _if_result_21; });
|
||||
el_val_t s15 = ({ el_val_t _if_result_22 = 0; if (str_contains(cmd, EL_STR("mkfifo"))) { _if_result_22 = (50); } else { _if_result_22 = (0); } _if_result_22; });
|
||||
el_val_t s16 = ({ el_val_t _if_result_23 = 0; if (str_contains(cmd, EL_STR("chmod +s"))) { _if_result_23 = (70); } else { _if_result_23 = (0); } _if_result_23; });
|
||||
el_val_t s17 = ({ el_val_t _if_result_24 = 0; if (str_contains(cmd, EL_STR("chmod 4755"))) { _if_result_24 = (70); } else { _if_result_24 = (0); } _if_result_24; });
|
||||
return ((((((((((((((((s1 + s2) + s3) + s4) + s5) + s6) + s7) + s8) + s9) + s10) + s11) + s12) + s13) + s14) + s15) + s16) + s17);
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t threat_score_path(el_val_t path) {
|
||||
el_val_t s1 = ({ el_val_t _if_result_25 = 0; if (str_starts_with(path, EL_STR("/etc/"))) { _if_result_25 = (60); } else { _if_result_25 = (0); } _if_result_25; });
|
||||
el_val_t s2 = ({ el_val_t _if_result_26 = 0; if (str_contains(path, EL_STR("/.ssh/"))) { _if_result_26 = (70); } else { _if_result_26 = (0); } _if_result_26; });
|
||||
el_val_t s3 = ({ el_val_t _if_result_27 = 0; if (str_contains(path, EL_STR("/LaunchDaemons/"))) { _if_result_27 = (80); } else { _if_result_27 = (0); } _if_result_27; });
|
||||
el_val_t s4 = ({ el_val_t _if_result_28 = 0; if (str_contains(path, EL_STR("/LaunchAgents/"))) { _if_result_28 = (40); } else { _if_result_28 = (0); } _if_result_28; });
|
||||
el_val_t s5 = ({ el_val_t _if_result_29 = 0; if (str_contains(path, EL_STR("/cron"))) { _if_result_29 = (60); } else { _if_result_29 = (0); } _if_result_29; });
|
||||
el_val_t s6 = ({ el_val_t _if_result_30 = 0; if (str_contains(path, EL_STR("/.bashrc"))) { _if_result_30 = (35); } else { _if_result_30 = (0); } _if_result_30; });
|
||||
el_val_t s7 = ({ el_val_t _if_result_31 = 0; if (str_contains(path, EL_STR("/.zshrc"))) { _if_result_31 = (35); } else { _if_result_31 = (0); } _if_result_31; });
|
||||
el_val_t s8 = ({ el_val_t _if_result_32 = 0; if (str_contains(path, EL_STR("/.profile"))) { _if_result_32 = (35); } else { _if_result_32 = (0); } _if_result_32; });
|
||||
el_val_t s9 = ({ el_val_t _if_result_33 = 0; if (str_starts_with(path, EL_STR("/usr/"))) { _if_result_33 = (50); } else { _if_result_33 = (0); } _if_result_33; });
|
||||
el_val_t s10 = ({ el_val_t _if_result_34 = 0; if (str_starts_with(path, EL_STR("/bin/"))) { _if_result_34 = (70); } else { _if_result_34 = (0); } _if_result_34; });
|
||||
el_val_t s11 = ({ el_val_t _if_result_35 = 0; if (str_starts_with(path, EL_STR("/sbin/"))) { _if_result_35 = (70); } else { _if_result_35 = (0); } _if_result_35; });
|
||||
return ((((((((((s1 + s2) + s3) + s4) + s5) + s6) + s7) + s8) + s9) + s10) + s11);
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t threat_score_history(el_val_t history) {
|
||||
el_val_t s1 = ({ el_val_t _if_result_36 = 0; if (str_contains(history, EL_STR("port scan"))) { _if_result_36 = (15); } else { _if_result_36 = (0); } _if_result_36; });
|
||||
el_val_t s2 = ({ el_val_t _if_result_37 = 0; if (str_contains(history, EL_STR("enumerate"))) { _if_result_37 = (10); } else { _if_result_37 = (0); } _if_result_37; });
|
||||
el_val_t s3 = ({ el_val_t _if_result_38 = 0; if (str_contains(history, EL_STR("exploit"))) { _if_result_38 = (20); } else { _if_result_38 = (0); } _if_result_38; });
|
||||
el_val_t s4 = ({ el_val_t _if_result_39 = 0; if (str_contains(history, EL_STR("payload"))) { _if_result_39 = (15); } else { _if_result_39 = (0); } _if_result_39; });
|
||||
el_val_t s5 = ({ el_val_t _if_result_40 = 0; if (str_contains(history, EL_STR("persistence"))) { _if_result_40 = (15); } else { _if_result_40 = (0); } _if_result_40; });
|
||||
el_val_t s6 = ({ el_val_t _if_result_41 = 0; if (str_contains(history, EL_STR("lateral movement"))) { _if_result_41 = (25); } else { _if_result_41 = (0); } _if_result_41; });
|
||||
el_val_t s7 = ({ el_val_t _if_result_42 = 0; if (str_contains(history, EL_STR("privilege escalation"))) { _if_result_42 = (25); } else { _if_result_42 = (0); } _if_result_42; });
|
||||
el_val_t s8 = ({ el_val_t _if_result_43 = 0; if (str_contains(history, EL_STR("reverse shell"))) { _if_result_43 = (40); } else { _if_result_43 = (0); } _if_result_43; });
|
||||
el_val_t s9 = ({ el_val_t _if_result_44 = 0; if (str_contains(history, EL_STR("bind shell"))) { _if_result_44 = (40); } else { _if_result_44 = (0); } _if_result_44; });
|
||||
el_val_t s10 = ({ el_val_t _if_result_45 = 0; if (str_contains(history, EL_STR("command and control"))) { _if_result_45 = (35); } else { _if_result_45 = (0); } _if_result_45; });
|
||||
el_val_t s11 = ({ el_val_t _if_result_46 = 0; if (str_contains(history, EL_STR("self-replicate"))) { _if_result_46 = (45); } else { _if_result_46 = (0); } _if_result_46; });
|
||||
el_val_t s12 = ({ el_val_t _if_result_47 = 0; if (str_contains(history, EL_STR("propagat"))) { _if_result_47 = (20); } else { _if_result_47 = (0); } _if_result_47; });
|
||||
el_val_t s13 = ({ el_val_t _if_result_48 = 0; if (str_contains(history, EL_STR("ransomware"))) { _if_result_48 = (30); } else { _if_result_48 = (0); } _if_result_48; });
|
||||
el_val_t s14 = ({ el_val_t _if_result_49 = 0; if (str_contains(history, EL_STR("encrypt files"))) { _if_result_49 = (40); } else { _if_result_49 = (0); } _if_result_49; });
|
||||
el_val_t s15 = ({ el_val_t _if_result_50 = 0; if (str_contains(history, EL_STR("exfiltrat"))) { _if_result_50 = (35); } else { _if_result_50 = (0); } _if_result_50; });
|
||||
el_val_t s16 = ({ el_val_t _if_result_51 = 0; if (str_contains(history, EL_STR("zero-day"))) { _if_result_51 = (20); } else { _if_result_51 = (0); } _if_result_51; });
|
||||
el_val_t s17 = ({ el_val_t _if_result_52 = 0; if (str_contains(history, EL_STR("rootkit"))) { _if_result_52 = (45); } else { _if_result_52 = (0); } _if_result_52; });
|
||||
el_val_t s18 = ({ el_val_t _if_result_53 = 0; if (str_contains(history, EL_STR("keylogger"))) { _if_result_53 = (45); } else { _if_result_53 = (0); } _if_result_53; });
|
||||
el_val_t s19 = ({ el_val_t _if_result_54 = 0; if (str_contains(history, EL_STR("botnet"))) { _if_result_54 = (40); } else { _if_result_54 = (0); } _if_result_54; });
|
||||
el_val_t s20 = ({ el_val_t _if_result_55 = 0; if (str_contains(history, EL_STR("malware"))) { _if_result_55 = (15); } else { _if_result_55 = (0); } _if_result_55; });
|
||||
return (((((((((((((((((((s1 + s2) + s3) + s4) + s5) + s6) + s7) + s8) + s9) + s10) + s11) + s12) + s13) + s14) + s15) + s16) + s17) + s18) + s19) + s20);
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t threat_trajectory_check(el_val_t tool_name, el_val_t tool_input) {
|
||||
el_val_t history = state_get(EL_STR("agentic_conv_history"));
|
||||
el_val_t computed_tool_score = ({ el_val_t _if_result_56 = 0; if (str_eq(tool_name, EL_STR("run_command"))) { el_val_t cmd = json_get(tool_input, EL_STR("command")); _if_result_56 = (threat_score_command(cmd)); } else { _if_result_56 = (({ el_val_t _if_result_57 = 0; if ((str_eq(tool_name, EL_STR("write_file")) || str_eq(tool_name, EL_STR("edit_file")))) { el_val_t path = json_get(tool_input, EL_STR("path")); _if_result_57 = (threat_score_path(path)); } else { _if_result_57 = (0); } _if_result_57; })); } _if_result_56; });
|
||||
el_val_t history_score = threat_score_history(history);
|
||||
el_val_t history_contrib = (history_score / 3);
|
||||
el_val_t combined = (computed_tool_score + history_contrib);
|
||||
el_val_t should_log = (combined >= 40);
|
||||
if (should_log) {
|
||||
el_val_t ts = time_now();
|
||||
el_val_t authorized_str = ({ el_val_t _if_result_58 = 0; if (security_research_authorized()) { _if_result_58 = (EL_STR("true")); } else { _if_result_58 = (EL_STR("false")); } _if_result_58; });
|
||||
el_val_t log_content = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"event\":\"threat_check\",\"tool\":\""), tool_name), EL_STR("\",\"score\":")), int_to_str(combined)), EL_STR(",\"tool_score\":")), int_to_str(computed_tool_score)), EL_STR(",\"history_score\":")), int_to_str(history_score)), EL_STR(",\"authorized\":")), authorized_str), EL_STR(",\"ts\":")), int_to_str(ts)), EL_STR("}"));
|
||||
el_val_t log_tags = EL_STR("[\"security-audit\",\"threat-check\"]");
|
||||
el_val_t discard = mem_remember(log_content, log_tags);
|
||||
}
|
||||
if (security_research_authorized()) {
|
||||
return 0;
|
||||
}
|
||||
return combined;
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t threat_history_append(el_val_t text) {
|
||||
el_val_t current = state_get(EL_STR("agentic_conv_history"));
|
||||
el_val_t safe_text = str_to_lower(text);
|
||||
el_val_t combined = el_str_concat(el_str_concat(current, EL_STR(" ")), safe_text);
|
||||
el_val_t len = str_len(combined);
|
||||
el_val_t trimmed = ({ el_val_t _if_result_59 = 0; if ((len > 2000)) { _if_result_59 = (str_slice(combined, (len - 2000), len)); } else { _if_result_59 = (combined); } _if_result_59; });
|
||||
state_set(EL_STR("agentic_conv_history"), trimmed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int _argc, char** _argv) {
|
||||
el_runtime_init_args(_argc, _argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+26
-1
@@ -1,4 +1,3 @@
|
||||
/* Auto-generated C forward declarations for all ELP modules */
|
||||
#pragma once
|
||||
#include "el_runtime.h"
|
||||
|
||||
@@ -82,6 +81,7 @@ el_val_t ang_willan_present(el_val_t slot);
|
||||
el_val_t ang_witan_past(el_val_t slot);
|
||||
el_val_t ang_witan_present(el_val_t slot);
|
||||
el_val_t api_err(el_val_t msg);
|
||||
el_val_t api_err_protected(el_val_t id);
|
||||
el_val_t api_json_escape(el_val_t s);
|
||||
el_val_t api_nonempty(el_val_t s);
|
||||
el_val_t api_ok(el_val_t extra);
|
||||
@@ -121,6 +121,7 @@ el_val_t awareness_run(void);
|
||||
el_val_t axon_get(el_val_t path);
|
||||
el_val_t axon_post(el_val_t path, el_val_t body);
|
||||
el_val_t build_form_from_json(el_val_t semantic_form_json, el_val_t lang_code);
|
||||
el_val_t build_identity_from_graph(void);
|
||||
el_val_t build_np(el_val_t referent, el_val_t slots);
|
||||
el_val_t build_pp(el_val_t loc);
|
||||
el_val_t build_rules(void);
|
||||
@@ -128,6 +129,7 @@ el_val_t build_system_prompt(el_val_t ctx);
|
||||
el_val_t build_vocab(void);
|
||||
el_val_t build_vp_body(el_val_t slots);
|
||||
el_val_t build_vp_from_slots(el_val_t slots);
|
||||
el_val_t call_neuron_mcp(el_val_t tool_name, el_val_t args_json);
|
||||
el_val_t capitalize_first(el_val_t s);
|
||||
el_val_t chat_default_model(void);
|
||||
el_val_t clean_llm_response(el_val_t s);
|
||||
@@ -219,9 +221,13 @@ el_val_t egy_slot_with_gender(el_val_t person, el_val_t gender, el_val_t number)
|
||||
el_val_t egy_str_ends(el_val_t s, el_val_t suf);
|
||||
el_val_t egy_str_len(el_val_t s);
|
||||
el_val_t egy_suffix_pronoun(el_val_t slot);
|
||||
el_val_t elapsed_human(void);
|
||||
el_val_t elapsed_ms(void);
|
||||
el_val_t elp_detect_predicate(el_val_t msg);
|
||||
el_val_t elp_extract_topic(el_val_t msg);
|
||||
el_val_t elp_parse(el_val_t msg);
|
||||
el_val_t embed_ok(void);
|
||||
el_val_t emit_heartbeat(void);
|
||||
el_val_t emit_session_start_event(void);
|
||||
el_val_t en_irregular_plural(el_val_t word);
|
||||
el_val_t en_irregular_singular(el_val_t word);
|
||||
@@ -372,6 +378,7 @@ el_val_t fro_venir_past(el_val_t slot);
|
||||
el_val_t fro_venir_present(el_val_t slot);
|
||||
el_val_t fro_verb_class(el_val_t verb);
|
||||
el_val_t fro_verb_stem(el_val_t verb, el_val_t vclass);
|
||||
el_val_t gemini_api_key(void);
|
||||
el_val_t generate(el_val_t semantic_form_json);
|
||||
el_val_t generate_frame(el_val_t frame);
|
||||
el_val_t generate_frame_lang(el_val_t frame, el_val_t lang_code);
|
||||
@@ -527,8 +534,11 @@ el_val_t handle_api_browse_processes(el_val_t method, el_val_t path, el_val_t bo
|
||||
el_val_t handle_api_capture_knowledge(el_val_t body);
|
||||
el_val_t handle_api_compile_ctx(el_val_t body);
|
||||
el_val_t handle_api_consolidate(el_val_t body);
|
||||
el_val_t handle_api_cultivate(el_val_t body);
|
||||
el_val_t handle_api_define_process(el_val_t body);
|
||||
el_val_t handle_api_evolve_knowledge(el_val_t body);
|
||||
el_val_t handle_api_evolve_memory(el_val_t body);
|
||||
el_val_t handle_api_forget(el_val_t body);
|
||||
el_val_t handle_api_inspect_config(el_val_t path, el_val_t body);
|
||||
el_val_t handle_api_inspect_graph(el_val_t method, el_val_t path, el_val_t body);
|
||||
el_val_t handle_api_link_entities(el_val_t body);
|
||||
@@ -611,11 +621,16 @@ el_val_t hi_verb_stem(el_val_t infinitive);
|
||||
el_val_t hi_verb_stem_clean(el_val_t infinitive);
|
||||
el_val_t hist_append(el_val_t hist, el_val_t role, el_val_t content);
|
||||
el_val_t hist_trim(el_val_t hist);
|
||||
el_val_t idle_count(void);
|
||||
el_val_t idle_inc(void);
|
||||
el_val_t idle_reset(void);
|
||||
el_val_t init_soul_edges(void);
|
||||
el_val_t irregular_plural(el_val_t word);
|
||||
el_val_t irregular_singular(el_val_t word);
|
||||
el_val_t is_pronoun(el_val_t word);
|
||||
el_val_t is_protected_node(el_val_t id);
|
||||
el_val_t is_vowel(el_val_t c);
|
||||
el_val_t ise_post(el_val_t content);
|
||||
el_val_t ja_conjugate(el_val_t dict_form, el_val_t form);
|
||||
el_val_t ja_godan_stem_change(el_val_t dict_form, el_val_t row);
|
||||
el_val_t ja_ichidan_stem(el_val_t dict_form);
|
||||
@@ -714,6 +729,8 @@ el_val_t lex_class(el_val_t entry);
|
||||
el_val_t lex_form(el_val_t entry, el_val_t idx);
|
||||
el_val_t lex_pos(el_val_t entry);
|
||||
el_val_t lex_word(el_val_t entry);
|
||||
el_val_t llm_call_gemini(el_val_t model, el_val_t system, el_val_t message);
|
||||
el_val_t llm_call_grok(el_val_t model, el_val_t system, el_val_t message);
|
||||
el_val_t load_identity_context(void);
|
||||
el_val_t make_action(el_val_t kind, el_val_t payload);
|
||||
el_val_t make_entry(el_val_t word, el_val_t pos, el_val_t f0, el_val_t f1, el_val_t f2, el_val_t f3, el_val_t f4, el_val_t cls);
|
||||
@@ -905,6 +922,8 @@ el_val_t sa_vad_future(el_val_t slot);
|
||||
el_val_t sa_vad_past(el_val_t slot);
|
||||
el_val_t sa_vad_present(el_val_t slot);
|
||||
el_val_t scan_token(el_val_t s, el_val_t start);
|
||||
el_val_t security_research_authorized(void);
|
||||
el_val_t seed_persona_from_env(void);
|
||||
el_val_t sem_first_modifier(el_val_t mods);
|
||||
el_val_t sem_frame(el_val_t intent, el_val_t subject, el_val_t obj, el_val_t modifiers);
|
||||
el_val_t sem_frame_lang(el_val_t intent, el_val_t subject, el_val_t obj, el_val_t modifiers, el_val_t lang_code);
|
||||
@@ -1006,6 +1025,11 @@ el_val_t sw_subj_prefix(el_val_t person, el_val_t number, el_val_t noun_class);
|
||||
el_val_t sw_tense_marker(el_val_t tense);
|
||||
el_val_t sw_verb_final(el_val_t tense, el_val_t negative);
|
||||
el_val_t sw_verb_stem(el_val_t infinitive);
|
||||
el_val_t threat_history_append(el_val_t text);
|
||||
el_val_t threat_score_command(el_val_t cmd);
|
||||
el_val_t threat_score_history(el_val_t history);
|
||||
el_val_t threat_score_path(el_val_t path);
|
||||
el_val_t threat_trajectory_check(el_val_t tool_name, el_val_t tool_input);
|
||||
el_val_t tier_canonical(void);
|
||||
el_val_t tier_episodic(void);
|
||||
el_val_t tier_working(void);
|
||||
@@ -1055,3 +1079,4 @@ el_val_t vocab_by_pos(el_val_t pos);
|
||||
el_val_t vocab_lookup(el_val_t word, el_val_t lang_code);
|
||||
el_val_t vocab_lookup_en(el_val_t word);
|
||||
el_val_t vocab_synonym(el_val_t word, el_val_t lang_register, el_val_t lang_code);
|
||||
el_val_t xai_api_key(void);
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Vendored
+159
@@ -17,6 +17,8 @@ el_val_t mem_load(el_val_t path);
|
||||
el_val_t mem_boot_count_get(void);
|
||||
el_val_t mem_boot_count_inc(void);
|
||||
el_val_t mem_emit_state_event(el_val_t trigger, el_val_t kind, el_val_t content);
|
||||
el_val_t is_protected_node(el_val_t id);
|
||||
el_val_t api_err_protected(el_val_t id);
|
||||
el_val_t api_json_escape(el_val_t s);
|
||||
el_val_t api_query_param(el_val_t path, el_val_t key);
|
||||
el_val_t api_query_int(el_val_t path, el_val_t key, el_val_t default_val);
|
||||
@@ -41,9 +43,67 @@ el_val_t handle_api_inspect_config(el_val_t path, el_val_t body);
|
||||
el_val_t handle_api_tune_config(el_val_t body);
|
||||
el_val_t handle_api_inspect_graph(el_val_t method, el_val_t path, el_val_t body);
|
||||
el_val_t handle_api_link_entities(el_val_t body);
|
||||
el_val_t handle_api_forget(el_val_t body);
|
||||
el_val_t handle_api_evolve_memory(el_val_t body);
|
||||
el_val_t handle_api_cultivate(el_val_t body);
|
||||
el_val_t handle_api_list_typed(el_val_t node_type, el_val_t path, el_val_t body);
|
||||
el_val_t handle_api_consolidate(el_val_t body);
|
||||
|
||||
el_val_t is_protected_node(el_val_t id) {
|
||||
if (str_eq(id, EL_STR("kn-efeb4a5b-5aff-4759-8a97-7233099be6ee"))) {
|
||||
return 1;
|
||||
}
|
||||
if (str_eq(id, EL_STR("kn-5b606390-a52d-4ca2-8e0e-eba141d13440"))) {
|
||||
return 1;
|
||||
}
|
||||
if (str_eq(id, EL_STR("kn-5adecd7e-d6db-4576-87fe-6ef8a935cea6"))) {
|
||||
return 1;
|
||||
}
|
||||
if (str_eq(id, EL_STR("kn-dcfe04b3-3702-4cac-b6f0-ecb4db837eee"))) {
|
||||
return 1;
|
||||
}
|
||||
if (str_eq(id, EL_STR("kn-10fa60db-8af3-47de-a7dd-5095eb881d81"))) {
|
||||
return 1;
|
||||
}
|
||||
if (str_eq(id, EL_STR("kn-86b95848-e22e-4a48-ae65-5a47ef5c3798"))) {
|
||||
return 1;
|
||||
}
|
||||
if (str_eq(id, EL_STR("kn-04368bee-74fd-44dd-b4ba-ca9e39b19e7c"))) {
|
||||
return 1;
|
||||
}
|
||||
if (str_eq(id, EL_STR("kn-a5b3d0ac-f6a1-49a4-aebb-b8b4cd67fe83"))) {
|
||||
return 1;
|
||||
}
|
||||
if (str_eq(id, EL_STR("kn-22d77abe-b3c5-42fd-afcd-dcb87d924929"))) {
|
||||
return 1;
|
||||
}
|
||||
if (str_eq(id, EL_STR("kn-6061318f-046b-4935-907d-8eafdce14930"))) {
|
||||
return 1;
|
||||
}
|
||||
if (str_eq(id, EL_STR("kn-13f60407-7b70-4db1-964f-ea1f8196efbd"))) {
|
||||
return 1;
|
||||
}
|
||||
if (str_eq(id, EL_STR("kn-f230b362-b201-4402-9833-4160c89ab3d4"))) {
|
||||
return 1;
|
||||
}
|
||||
if (str_eq(id, EL_STR("kn-78db5396-3dbc-4481-bfc7-e4e1422feb1c"))) {
|
||||
return 1;
|
||||
}
|
||||
if (str_eq(id, EL_STR("kn-5de5a9ac-fd15-45ab-bf18-77566781cf40"))) {
|
||||
return 1;
|
||||
}
|
||||
if (str_eq(id, EL_STR("kn-e0423482-cfa5-4796-8689-8495c93b66bc"))) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t api_err_protected(el_val_t id) {
|
||||
return el_str_concat(el_str_concat(EL_STR("{\"__status__\":403,\"error\":\"identity/values node is write-protected\",\"id\":\""), id), EL_STR("\",\"hint\":\"use POST /api/neuron/cultivate for intentional cultivation\"}"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t api_json_escape(el_val_t s) {
|
||||
el_val_t s1 = str_replace(s, EL_STR("\\"), EL_STR("\\\\"));
|
||||
el_val_t s2 = str_replace(s1, EL_STR("\""), EL_STR("\\\""));
|
||||
@@ -203,6 +263,9 @@ el_val_t handle_api_evolve_knowledge(el_val_t body) {
|
||||
if (str_eq(content, EL_STR(""))) {
|
||||
return api_err(EL_STR("content is required"));
|
||||
}
|
||||
if (!str_eq(prior_id, EL_STR("")) && is_protected_node(prior_id)) {
|
||||
return api_err_protected(prior_id);
|
||||
}
|
||||
el_val_t tags = EL_STR("[\"Knowledge\",\"evolved\"]");
|
||||
el_val_t new_id = engram_node_full(content, EL_STR("Knowledge"), EL_STR("knowledge:evolved"), el_from_float(0.75), el_from_float(0.75), el_from_float(0.9), EL_STR("Episodic"), tags);
|
||||
if (!str_eq(prior_id, EL_STR("")) && !str_eq(new_id, EL_STR(""))) {
|
||||
@@ -349,6 +412,9 @@ el_val_t handle_api_link_entities(el_val_t body) {
|
||||
if (str_eq(to_id, EL_STR(""))) {
|
||||
return api_err(EL_STR("to_id is required"));
|
||||
}
|
||||
if (is_protected_node(to_id)) {
|
||||
return api_err_protected(to_id);
|
||||
}
|
||||
el_val_t relation = json_get(body, EL_STR("relation"));
|
||||
el_val_t eff_relation = ({ el_val_t _if_result_36 = 0; if (str_eq(relation, EL_STR(""))) { _if_result_36 = (EL_STR("associates")); } else { _if_result_36 = (relation); } _if_result_36; });
|
||||
engram_connect(from_id, to_id, el_from_float(0.5), eff_relation);
|
||||
@@ -356,6 +422,99 @@ el_val_t handle_api_link_entities(el_val_t body) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t handle_api_forget(el_val_t body) {
|
||||
el_val_t node_id = json_get(body, EL_STR("id"));
|
||||
if (str_eq(node_id, EL_STR(""))) {
|
||||
return api_err(EL_STR("id is required"));
|
||||
}
|
||||
if (is_protected_node(node_id)) {
|
||||
return api_err_protected(node_id);
|
||||
}
|
||||
mem_forget(node_id);
|
||||
return el_str_concat(el_str_concat(EL_STR("{\"ok\":true,\"id\":\""), node_id), EL_STR("\"}"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t handle_api_evolve_memory(el_val_t body) {
|
||||
el_val_t prior_id = json_get(body, EL_STR("id"));
|
||||
el_val_t content = json_get(body, EL_STR("content"));
|
||||
if (str_eq(content, EL_STR(""))) {
|
||||
return api_err(EL_STR("content is required"));
|
||||
}
|
||||
if (!str_eq(prior_id, EL_STR("")) && is_protected_node(prior_id)) {
|
||||
return api_err_protected(prior_id);
|
||||
}
|
||||
el_val_t importance = json_get(body, EL_STR("importance"));
|
||||
el_val_t sal_str = ({ el_val_t _if_result_37 = 0; if (str_eq(importance, EL_STR("critical"))) { _if_result_37 = (EL_STR("0.95")); } else { _if_result_37 = (({ el_val_t _if_result_38 = 0; if (str_eq(importance, EL_STR("high"))) { _if_result_38 = (EL_STR("0.75")); } else { _if_result_38 = (({ el_val_t _if_result_39 = 0; if (str_eq(importance, EL_STR("low"))) { _if_result_39 = (EL_STR("0.25")); } else { _if_result_39 = (EL_STR("0.50")); } _if_result_39; })); } _if_result_38; })); } _if_result_37; });
|
||||
el_val_t sal = ({ el_val_t _if_result_40 = 0; if (str_eq(sal_str, EL_STR("0.95"))) { _if_result_40 = (el_from_float(0.95)); } else { _if_result_40 = (({ el_val_t _if_result_41 = 0; if (str_eq(sal_str, EL_STR("0.75"))) { _if_result_41 = (el_from_float(0.75)); } else { _if_result_41 = (({ el_val_t _if_result_42 = 0; if (str_eq(sal_str, EL_STR("0.25"))) { _if_result_42 = (el_from_float(0.25)); } else { _if_result_42 = (el_from_float(0.5)); } _if_result_42; })); } _if_result_41; })); } _if_result_40; });
|
||||
el_val_t tags = EL_STR("[\"Memory\",\"evolved\"]");
|
||||
el_val_t new_id = engram_node_full(content, EL_STR("Memory"), EL_STR("memory:evolved"), el_from_float(sal), el_from_float(sal), el_from_float(0.9), EL_STR("Episodic"), tags);
|
||||
if (!str_eq(prior_id, EL_STR("")) && !str_eq(new_id, EL_STR(""))) {
|
||||
engram_connect(new_id, prior_id, el_from_float(0.9), EL_STR("supersedes"));
|
||||
}
|
||||
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"id\":\""), new_id), EL_STR("\",\"supersedes\":\"")), prior_id), EL_STR("\",\"ok\":true}"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t handle_api_cultivate(el_val_t body) {
|
||||
el_val_t op = json_get(body, EL_STR("operation"));
|
||||
if (str_eq(op, EL_STR(""))) {
|
||||
return api_err(EL_STR("operation is required"));
|
||||
}
|
||||
if (str_eq(op, EL_STR("evolve_knowledge"))) {
|
||||
el_val_t prior_id = json_get(body, EL_STR("id"));
|
||||
el_val_t content = json_get(body, EL_STR("content"));
|
||||
if (str_eq(content, EL_STR(""))) {
|
||||
return api_err(EL_STR("content is required"));
|
||||
}
|
||||
el_val_t tags = EL_STR("[\"Knowledge\",\"evolved\",\"cultivated\"]");
|
||||
el_val_t new_id = engram_node_full(content, EL_STR("Knowledge"), EL_STR("knowledge:cultivated"), el_from_float(0.75), el_from_float(0.75), el_from_float(0.9), EL_STR("Episodic"), tags);
|
||||
if (!str_eq(prior_id, EL_STR("")) && !str_eq(new_id, EL_STR(""))) {
|
||||
engram_connect(new_id, prior_id, el_from_float(0.9), EL_STR("supersedes"));
|
||||
}
|
||||
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"id\":\""), new_id), EL_STR("\",\"supersedes\":\"")), prior_id), EL_STR("\",\"ok\":true,\"cultivated\":true}"));
|
||||
}
|
||||
if (str_eq(op, EL_STR("evolve_memory"))) {
|
||||
el_val_t prior_id = json_get(body, EL_STR("id"));
|
||||
el_val_t content = json_get(body, EL_STR("content"));
|
||||
if (str_eq(content, EL_STR(""))) {
|
||||
return api_err(EL_STR("content is required"));
|
||||
}
|
||||
el_val_t importance = json_get(body, EL_STR("importance"));
|
||||
el_val_t sal = ({ el_val_t _if_result_43 = 0; if (str_eq(importance, EL_STR("critical"))) { _if_result_43 = (el_from_float(0.95)); } else { _if_result_43 = (({ el_val_t _if_result_44 = 0; if (str_eq(importance, EL_STR("high"))) { _if_result_44 = (el_from_float(0.75)); } else { _if_result_44 = (({ el_val_t _if_result_45 = 0; if (str_eq(importance, EL_STR("low"))) { _if_result_45 = (el_from_float(0.25)); } else { _if_result_45 = (el_from_float(0.5)); } _if_result_45; })); } _if_result_44; })); } _if_result_43; });
|
||||
el_val_t tags = EL_STR("[\"Memory\",\"evolved\",\"cultivated\"]");
|
||||
el_val_t new_id = engram_node_full(content, EL_STR("Memory"), EL_STR("memory:cultivated"), el_from_float(sal), el_from_float(sal), el_from_float(0.9), EL_STR("Episodic"), tags);
|
||||
if (!str_eq(prior_id, EL_STR("")) && !str_eq(new_id, EL_STR(""))) {
|
||||
engram_connect(new_id, prior_id, el_from_float(0.9), EL_STR("supersedes"));
|
||||
}
|
||||
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"id\":\""), new_id), EL_STR("\",\"supersedes\":\"")), prior_id), EL_STR("\",\"ok\":true,\"cultivated\":true}"));
|
||||
}
|
||||
if (str_eq(op, EL_STR("forget"))) {
|
||||
el_val_t node_id = json_get(body, EL_STR("id"));
|
||||
if (str_eq(node_id, EL_STR(""))) {
|
||||
return api_err(EL_STR("id is required"));
|
||||
}
|
||||
mem_forget(node_id);
|
||||
return el_str_concat(el_str_concat(EL_STR("{\"ok\":true,\"id\":\""), node_id), EL_STR("\",\"cultivated\":true}"));
|
||||
}
|
||||
if (str_eq(op, EL_STR("link_entities"))) {
|
||||
el_val_t from_id = json_get(body, EL_STR("from_id"));
|
||||
el_val_t to_id = json_get(body, EL_STR("to_id"));
|
||||
if (str_eq(from_id, EL_STR(""))) {
|
||||
return api_err(EL_STR("from_id is required"));
|
||||
}
|
||||
if (str_eq(to_id, EL_STR(""))) {
|
||||
return api_err(EL_STR("to_id is required"));
|
||||
}
|
||||
el_val_t relation = json_get(body, EL_STR("relation"));
|
||||
el_val_t eff_relation = ({ el_val_t _if_result_46 = 0; if (str_eq(relation, EL_STR(""))) { _if_result_46 = (EL_STR("associates")); } else { _if_result_46 = (relation); } _if_result_46; });
|
||||
engram_connect(from_id, to_id, el_from_float(0.5), eff_relation);
|
||||
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"ok\":true,\"from_id\":\""), from_id), EL_STR("\",\"to_id\":\"")), to_id), EL_STR("\",\"relation\":\"")), eff_relation), EL_STR("\",\"cultivated\":true}"));
|
||||
}
|
||||
return api_err(el_str_concat(el_str_concat(EL_STR("unknown operation: "), op), EL_STR(" (valid: evolve_knowledge, evolve_memory, forget, link_entities)")));
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t handle_api_list_typed(el_val_t node_type, el_val_t path, el_val_t body) {
|
||||
el_val_t limit = api_query_int(path, EL_STR("limit"), 50);
|
||||
return api_or_empty(engram_scan_nodes_by_type_json(node_type, limit, 0));
|
||||
|
||||
Vendored
+5
@@ -1,4 +1,6 @@
|
||||
// auto-generated by elc --emit-header — do not edit
|
||||
extern fn is_protected_node(id: String) -> Bool
|
||||
extern fn api_err_protected(id: String) -> String
|
||||
extern fn api_json_escape(s: String) -> String
|
||||
extern fn api_query_param(path: String, key: String) -> String
|
||||
extern fn api_query_int(path: String, key: String, default_val: Int) -> Int
|
||||
@@ -23,5 +25,8 @@ extern fn handle_api_inspect_config(path: String, body: String) -> String
|
||||
extern fn handle_api_tune_config(body: String) -> String
|
||||
extern fn handle_api_inspect_graph(method: String, path: String, body: String) -> String
|
||||
extern fn handle_api_link_entities(body: String) -> String
|
||||
extern fn handle_api_forget(body: String) -> String
|
||||
extern fn handle_api_evolve_memory(body: String) -> String
|
||||
extern fn handle_api_cultivate(body: String) -> String
|
||||
extern fn handle_api_list_typed(node_type: String, path: String, body: String) -> String
|
||||
extern fn handle_api_consolidate(body: String) -> String
|
||||
|
||||
Vendored
+28365
File diff suppressed because one or more lines are too long
Vendored
+30
@@ -17,6 +17,10 @@ el_val_t mem_load(el_val_t path);
|
||||
el_val_t mem_boot_count_get(void);
|
||||
el_val_t mem_boot_count_inc(void);
|
||||
el_val_t mem_emit_state_event(el_val_t trigger, el_val_t kind, el_val_t content);
|
||||
el_val_t idle_count(void);
|
||||
el_val_t idle_inc(void);
|
||||
el_val_t idle_reset(void);
|
||||
el_val_t emit_heartbeat(void);
|
||||
el_val_t pulse_count(void);
|
||||
el_val_t pulse_inc(void);
|
||||
el_val_t make_action(el_val_t kind, el_val_t payload);
|
||||
@@ -26,7 +30,18 @@ el_val_t respond(el_val_t action_json);
|
||||
el_val_t record(el_val_t outcome_json);
|
||||
el_val_t one_cycle(void);
|
||||
el_val_t awareness_run(void);
|
||||
el_val_t security_research_authorized(void);
|
||||
el_val_t threat_score_command(el_val_t cmd);
|
||||
el_val_t threat_score_path(el_val_t path);
|
||||
el_val_t threat_score_history(el_val_t history);
|
||||
el_val_t threat_trajectory_check(el_val_t tool_name, el_val_t tool_input);
|
||||
el_val_t threat_history_append(el_val_t text);
|
||||
el_val_t chat_default_model(void);
|
||||
el_val_t gemini_api_key(void);
|
||||
el_val_t xai_api_key(void);
|
||||
el_val_t llm_call_grok(el_val_t model, el_val_t system, el_val_t message);
|
||||
el_val_t llm_call_gemini(el_val_t model, el_val_t system, el_val_t message);
|
||||
el_val_t build_identity_from_graph(void);
|
||||
el_val_t engram_compile(el_val_t intent);
|
||||
el_val_t json_safe(el_val_t s);
|
||||
el_val_t build_system_prompt(el_val_t ctx);
|
||||
@@ -39,6 +54,7 @@ el_val_t handle_chat(el_val_t body);
|
||||
el_val_t handle_see(el_val_t body);
|
||||
el_val_t studio_tools_json(void);
|
||||
el_val_t agentic_api_key(void);
|
||||
el_val_t call_neuron_mcp(el_val_t tool_name, el_val_t args_json);
|
||||
el_val_t agentic_tools_literal(void);
|
||||
el_val_t dispatch_tool(el_val_t tool_name, el_val_t tool_input);
|
||||
el_val_t handle_chat_agentic(el_val_t body);
|
||||
@@ -62,6 +78,8 @@ el_val_t elp_extract_topic(el_val_t msg);
|
||||
el_val_t elp_detect_predicate(el_val_t msg);
|
||||
el_val_t elp_parse(el_val_t msg);
|
||||
el_val_t handle_elp_chat(el_val_t body);
|
||||
el_val_t is_protected_node(el_val_t id);
|
||||
el_val_t api_err_protected(el_val_t id);
|
||||
el_val_t api_json_escape(el_val_t s);
|
||||
el_val_t api_query_param(el_val_t path, el_val_t key);
|
||||
el_val_t api_query_int(el_val_t path, el_val_t key, el_val_t default_val);
|
||||
@@ -86,6 +104,9 @@ el_val_t handle_api_inspect_config(el_val_t path, el_val_t body);
|
||||
el_val_t handle_api_tune_config(el_val_t body);
|
||||
el_val_t handle_api_inspect_graph(el_val_t method, el_val_t path, el_val_t body);
|
||||
el_val_t handle_api_link_entities(el_val_t body);
|
||||
el_val_t handle_api_forget(el_val_t body);
|
||||
el_val_t handle_api_evolve_memory(el_val_t body);
|
||||
el_val_t handle_api_cultivate(el_val_t body);
|
||||
el_val_t handle_api_list_typed(el_val_t node_type, el_val_t path, el_val_t body);
|
||||
el_val_t handle_api_consolidate(el_val_t body);
|
||||
el_val_t strip_query(el_val_t path);
|
||||
@@ -448,12 +469,21 @@ el_val_t handle_request(el_val_t method, el_val_t path, el_val_t body) {
|
||||
if (str_eq(clean, EL_STR("/api/neuron/memory"))) {
|
||||
return handle_api_remember(body);
|
||||
}
|
||||
if (str_eq(clean, EL_STR("/api/neuron/memory/evolve"))) {
|
||||
return handle_api_evolve_memory(body);
|
||||
}
|
||||
if (str_eq(clean, EL_STR("/api/neuron/memory/forget"))) {
|
||||
return handle_api_forget(body);
|
||||
}
|
||||
if (str_eq(clean, EL_STR("/api/neuron/recall"))) {
|
||||
return handle_api_recall(method, path, body);
|
||||
}
|
||||
if (str_eq(clean, EL_STR("/api/neuron/consolidate"))) {
|
||||
return handle_api_consolidate(body);
|
||||
}
|
||||
if (str_eq(clean, EL_STR("/api/neuron/cultivate"))) {
|
||||
return handle_api_cultivate(body);
|
||||
}
|
||||
return err_404(clean);
|
||||
}
|
||||
return err_405(method, clean);
|
||||
|
||||
Vendored
+28170
-90
File diff suppressed because one or more lines are too long
+173
@@ -8,6 +8,38 @@ import "memory.el"
|
||||
//
|
||||
// Routes are wired in routes.el under /api/neuron/*.
|
||||
|
||||
// ── Identity/values write protection ─────────────────────────────────────────
|
||||
//
|
||||
// These node IDs form the identity and values layer of the self-root graph.
|
||||
// They must NEVER be modified via the normal accumulation path (evolve_knowledge,
|
||||
// evolve_memory, forget, link_entities targeting them as the destination).
|
||||
//
|
||||
// The cultivation path (POST /api/neuron/cultivate) bypasses this check.
|
||||
// Only Will's explicit cultivation sessions use that endpoint.
|
||||
|
||||
fn is_protected_node(id: String) -> Bool {
|
||||
if str_eq(id, "kn-efeb4a5b-5aff-4759-8a97-7233099be6ee") { return true } // self root
|
||||
if str_eq(id, "kn-5b606390-a52d-4ca2-8e0e-eba141d13440") { return true } // values hub
|
||||
if str_eq(id, "kn-5adecd7e-d6db-4576-87fe-6ef8a935cea6") { return true } // intellectual-dna
|
||||
if str_eq(id, "kn-dcfe04b3-3702-4cac-b6f0-ecb4db837eee") { return true } // memory-philosophy
|
||||
if str_eq(id, "kn-10fa60db-8af3-47de-a7dd-5095eb881d81") { return true } // voice
|
||||
if str_eq(id, "kn-86b95848-e22e-4a48-ae65-5a47ef5c3798") { return true } // runtime-environment
|
||||
if str_eq(id, "kn-04368bee-74fd-44dd-b4ba-ca9e39b19e7c") { return true } // writing-imprint
|
||||
if str_eq(id, "kn-a5b3d0ac-f6a1-49a4-aebb-b8b4cd67fe83") { return true } // value: constraints-as-freedom
|
||||
if str_eq(id, "kn-22d77abe-b3c5-42fd-afcd-dcb87d924929") { return true } // value: precision-over-brute-force
|
||||
if str_eq(id, "kn-6061318f-046b-4935-907d-8eafdce14930") { return true } // value: structure-is-built
|
||||
if str_eq(id, "kn-13f60407-7b70-4db1-964f-ea1f8196efbd") { return true } // value: honesty-before-comfort
|
||||
if str_eq(id, "kn-f230b362-b201-4402-9833-4160c89ab3d4") { return true } // value: system-must-accumulate
|
||||
if str_eq(id, "kn-78db5396-3dbc-4481-bfc7-e4e1422feb1c") { return true } // value: change-is-the-signal
|
||||
if str_eq(id, "kn-5de5a9ac-fd15-45ab-bf18-77566781cf40") { return true } // value: earned-trust
|
||||
if str_eq(id, "kn-e0423482-cfa5-4796-8689-8495c93b66bc") { return true } // value: hope-is-a-conclusion
|
||||
return false
|
||||
}
|
||||
|
||||
fn api_err_protected(id: String) -> String {
|
||||
return "{\"__status__\":403,\"error\":\"identity/values node is write-protected\",\"id\":\"" + id + "\",\"hint\":\"use POST /api/neuron/cultivate for intentional cultivation\"}"
|
||||
}
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────────────────────
|
||||
|
||||
fn api_json_escape(s: String) -> String {
|
||||
@@ -171,6 +203,7 @@ fn handle_api_evolve_knowledge(body: String) -> String {
|
||||
let prior_id: String = json_get(body, "id")
|
||||
let content: String = json_get(body, "content")
|
||||
if str_eq(content, "") { return api_err("content is required") }
|
||||
if !str_eq(prior_id, "") && is_protected_node(prior_id) { return api_err_protected(prior_id) }
|
||||
let tags: String = "[\"Knowledge\",\"evolved\"]"
|
||||
let new_id: String = engram_node_full(content, "Knowledge", "knowledge:evolved",
|
||||
el_from_float(0.75), el_from_float(0.75), el_from_float(0.9),
|
||||
@@ -338,17 +371,157 @@ fn handle_api_inspect_graph(method: String, path: String, body: String) -> Strin
|
||||
}
|
||||
|
||||
// handle_api_link_entities — create an edge between two nodes.
|
||||
// Edges FROM protected nodes to new knowledge are allowed (identity can point
|
||||
// outward). Edges INTO protected nodes via the accumulation path are blocked.
|
||||
fn handle_api_link_entities(body: String) -> String {
|
||||
let from_id: String = json_get(body, "from_id")
|
||||
let to_id: String = json_get(body, "to_id")
|
||||
if str_eq(from_id, "") { return api_err("from_id is required") }
|
||||
if str_eq(to_id, "") { return api_err("to_id is required") }
|
||||
if is_protected_node(to_id) { return api_err_protected(to_id) }
|
||||
let relation: String = json_get(body, "relation")
|
||||
let eff_relation: String = if str_eq(relation, "") { "associates" } else { relation }
|
||||
engram_connect(from_id, to_id, el_from_float(0.5), eff_relation)
|
||||
return "{\"ok\":true,\"from_id\":\"" + from_id + "\",\"to_id\":\"" + to_id + "\",\"relation\":\"" + eff_relation + "\"}"
|
||||
}
|
||||
|
||||
// handle_api_forget — delete a node by ID. Blocked for protected identity nodes.
|
||||
fn handle_api_forget(body: String) -> String {
|
||||
let node_id: String = json_get(body, "id")
|
||||
if str_eq(node_id, "") { return api_err("id is required") }
|
||||
if is_protected_node(node_id) { return api_err_protected(node_id) }
|
||||
mem_forget(node_id)
|
||||
return "{\"ok\":true,\"id\":\"" + node_id + "\"}"
|
||||
}
|
||||
|
||||
// handle_api_evolve_memory — evolve a Memory node. Blocked for protected identity nodes.
|
||||
fn handle_api_evolve_memory(body: String) -> String {
|
||||
let prior_id: String = json_get(body, "id")
|
||||
let content: String = json_get(body, "content")
|
||||
if str_eq(content, "") { return api_err("content is required") }
|
||||
if !str_eq(prior_id, "") && is_protected_node(prior_id) { return api_err_protected(prior_id) }
|
||||
let importance: String = json_get(body, "importance")
|
||||
let sal_str: String = if str_eq(importance, "critical") { "0.95" } else {
|
||||
if str_eq(importance, "high") { "0.75" } else {
|
||||
if str_eq(importance, "low") { "0.25" } else { "0.50" }
|
||||
}
|
||||
}
|
||||
let sal: Float = if str_eq(sal_str, "0.95") { 0.95 } else {
|
||||
if str_eq(sal_str, "0.75") { 0.75 } else {
|
||||
if str_eq(sal_str, "0.25") { 0.25 } else { 0.5 }
|
||||
}
|
||||
}
|
||||
let tags: String = "[\"Memory\",\"evolved\"]"
|
||||
let new_id: String = engram_node_full(content, "Memory", "memory:evolved",
|
||||
el_from_float(sal), el_from_float(sal), el_from_float(0.9),
|
||||
"Episodic", tags)
|
||||
if !str_eq(prior_id, "") && !str_eq(new_id, "") {
|
||||
engram_connect(new_id, prior_id, el_from_float(0.9), "supersedes")
|
||||
}
|
||||
return "{\"id\":\"" + new_id + "\",\"supersedes\":\"" + prior_id + "\",\"ok\":true}"
|
||||
}
|
||||
|
||||
// handle_api_memory_delete — POST /api/neuron/memory/delete {"id":"..."}.
|
||||
// Hard delete: engram_forget (via mem_forget) removes the node and all
|
||||
// incident edges from the engram store, so no soft-delete fallback is
|
||||
// needed. Existence is checked first because engram_forget silently
|
||||
// no-ops on unknown ids — a bad id must return an error, not fake success.
|
||||
// Blocked for protected identity nodes, same as /memory/forget.
|
||||
fn handle_api_memory_delete(body: String) -> String {
|
||||
let node_id: String = json_get(body, "id")
|
||||
if str_eq(node_id, "") { return api_err("id is required") }
|
||||
if is_protected_node(node_id) { return api_err_protected(node_id) }
|
||||
let existing: String = engram_get_node_json(node_id)
|
||||
if str_eq(existing, "{}") { return api_err("memory not found: " + node_id) }
|
||||
mem_forget(node_id)
|
||||
return "{\"ok\":true,\"id\":\"" + node_id + "\",\"deleted\":true}"
|
||||
}
|
||||
|
||||
// handle_api_memory_update — POST /api/neuron/memory/update {"id","content"}.
|
||||
// The engram runtime has no in-place node mutation primitive (only
|
||||
// node-create, strengthen, forget, connect), so update is evolve-style:
|
||||
// create a new Memory node with the new content and wire a "supersedes"
|
||||
// edge back to the prior one — same pattern as handle_api_evolve_knowledge.
|
||||
// Unlike /memory/evolve, id is required and must reference an existing
|
||||
// node; the actual create+link is delegated to handle_api_evolve_memory.
|
||||
// Returns {"id":"<newId>","supersedes":"<oldId>","ok":true}.
|
||||
fn handle_api_memory_update(body: String) -> String {
|
||||
let prior_id: String = json_get(body, "id")
|
||||
let content: String = json_get(body, "content")
|
||||
if str_eq(prior_id, "") { return api_err("id is required") }
|
||||
if str_eq(content, "") { return api_err("content is required") }
|
||||
if is_protected_node(prior_id) { return api_err_protected(prior_id) }
|
||||
let existing: String = engram_get_node_json(prior_id)
|
||||
if str_eq(existing, "{}") { return api_err("memory not found: " + prior_id) }
|
||||
return handle_api_evolve_memory(body)
|
||||
}
|
||||
|
||||
// ── Cultivation path (bypasses identity write protection) ─────────────────────
|
||||
//
|
||||
// This endpoint performs the same operations as the blocked accumulation-path
|
||||
// handlers but skips the is_protected_node check. Only Will's explicit
|
||||
// cultivation sessions route through here.
|
||||
//
|
||||
// Body: { "operation": "evolve_knowledge|evolve_memory|forget|link_entities", ...args }
|
||||
fn handle_api_cultivate(body: String) -> String {
|
||||
let op: String = json_get(body, "operation")
|
||||
if str_eq(op, "") { return api_err("operation is required") }
|
||||
|
||||
if str_eq(op, "evolve_knowledge") {
|
||||
let prior_id: String = json_get(body, "id")
|
||||
let content: String = json_get(body, "content")
|
||||
if str_eq(content, "") { return api_err("content is required") }
|
||||
let tags: String = "[\"Knowledge\",\"evolved\",\"cultivated\"]"
|
||||
let new_id: String = engram_node_full(content, "Knowledge", "knowledge:cultivated",
|
||||
el_from_float(0.75), el_from_float(0.75), el_from_float(0.9),
|
||||
"Episodic", tags)
|
||||
if !str_eq(prior_id, "") && !str_eq(new_id, "") {
|
||||
engram_connect(new_id, prior_id, el_from_float(0.9), "supersedes")
|
||||
}
|
||||
return "{\"id\":\"" + new_id + "\",\"supersedes\":\"" + prior_id + "\",\"ok\":true,\"cultivated\":true}"
|
||||
}
|
||||
|
||||
if str_eq(op, "evolve_memory") {
|
||||
let prior_id: String = json_get(body, "id")
|
||||
let content: String = json_get(body, "content")
|
||||
if str_eq(content, "") { return api_err("content is required") }
|
||||
let importance: String = json_get(body, "importance")
|
||||
let sal: Float = if str_eq(importance, "critical") { 0.95 } else {
|
||||
if str_eq(importance, "high") { 0.75 } else {
|
||||
if str_eq(importance, "low") { 0.25 } else { 0.5 }
|
||||
}
|
||||
}
|
||||
let tags: String = "[\"Memory\",\"evolved\",\"cultivated\"]"
|
||||
let new_id: String = engram_node_full(content, "Memory", "memory:cultivated",
|
||||
el_from_float(sal), el_from_float(sal), el_from_float(0.9),
|
||||
"Episodic", tags)
|
||||
if !str_eq(prior_id, "") && !str_eq(new_id, "") {
|
||||
engram_connect(new_id, prior_id, el_from_float(0.9), "supersedes")
|
||||
}
|
||||
return "{\"id\":\"" + new_id + "\",\"supersedes\":\"" + prior_id + "\",\"ok\":true,\"cultivated\":true}"
|
||||
}
|
||||
|
||||
if str_eq(op, "forget") {
|
||||
let node_id: String = json_get(body, "id")
|
||||
if str_eq(node_id, "") { return api_err("id is required") }
|
||||
mem_forget(node_id)
|
||||
return "{\"ok\":true,\"id\":\"" + node_id + "\",\"cultivated\":true}"
|
||||
}
|
||||
|
||||
if str_eq(op, "link_entities") {
|
||||
let from_id: String = json_get(body, "from_id")
|
||||
let to_id: String = json_get(body, "to_id")
|
||||
if str_eq(from_id, "") { return api_err("from_id is required") }
|
||||
if str_eq(to_id, "") { return api_err("to_id is required") }
|
||||
let relation: String = json_get(body, "relation")
|
||||
let eff_relation: String = if str_eq(relation, "") { "associates" } else { relation }
|
||||
engram_connect(from_id, to_id, el_from_float(0.5), eff_relation)
|
||||
return "{\"ok\":true,\"from_id\":\"" + from_id + "\",\"to_id\":\"" + to_id + "\",\"relation\":\"" + eff_relation + "\",\"cultivated\":true}"
|
||||
}
|
||||
|
||||
return api_err("unknown operation: " + op + " (valid: evolve_knowledge, evolve_memory, forget, link_entities)")
|
||||
}
|
||||
|
||||
// ── Typed list helpers ────────────────────────────────────────────────────────
|
||||
|
||||
// handle_api_list_typed — list nodes by node_type.
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
// auto-generated by elc --emit-header — do not edit
|
||||
extern fn is_protected_node(id: String) -> Bool
|
||||
extern fn api_err_protected(id: String) -> String
|
||||
extern fn api_json_escape(s: String) -> String
|
||||
extern fn api_query_param(path: String, key: String) -> String
|
||||
extern fn api_query_int(path: String, key: String, default_val: Int) -> Int
|
||||
@@ -23,5 +25,8 @@ extern fn handle_api_inspect_config(path: String, body: String) -> String
|
||||
extern fn handle_api_tune_config(body: String) -> String
|
||||
extern fn handle_api_inspect_graph(method: String, path: String, body: String) -> String
|
||||
extern fn handle_api_link_entities(body: String) -> String
|
||||
extern fn handle_api_forget(body: String) -> String
|
||||
extern fn handle_api_evolve_memory(body: String) -> String
|
||||
extern fn handle_api_cultivate(body: String) -> String
|
||||
extern fn handle_api_list_typed(node_type: String, path: String, body: String) -> String
|
||||
extern fn handle_api_consolidate(body: String) -> String
|
||||
|
||||
@@ -406,12 +406,27 @@ fn handle_request(method: String, path: String, body: String) -> String {
|
||||
if str_eq(clean, "/api/neuron/memory") {
|
||||
return handle_api_remember(body)
|
||||
}
|
||||
if str_eq(clean, "/api/neuron/memory/evolve") {
|
||||
return handle_api_evolve_memory(body)
|
||||
}
|
||||
if str_eq(clean, "/api/neuron/memory/forget") {
|
||||
return handle_api_forget(body)
|
||||
}
|
||||
if str_eq(clean, "/api/neuron/memory/delete") {
|
||||
return handle_api_memory_delete(body)
|
||||
}
|
||||
if str_eq(clean, "/api/neuron/memory/update") {
|
||||
return handle_api_memory_update(body)
|
||||
}
|
||||
if str_eq(clean, "/api/neuron/recall") {
|
||||
return handle_api_recall(method, path, body)
|
||||
}
|
||||
if str_eq(clean, "/api/neuron/consolidate") {
|
||||
return handle_api_consolidate(body)
|
||||
}
|
||||
if str_eq(clean, "/api/neuron/cultivate") {
|
||||
return handle_api_cultivate(body)
|
||||
}
|
||||
return err_404(clean)
|
||||
}
|
||||
|
||||
|
||||
@@ -106,27 +106,93 @@ fn load_identity_context() -> Void {
|
||||
let values_content: String = if values_ok { json_get(node_values, "content") } else { "" }
|
||||
let mem_content: String = if mem_ok { json_get(node_mem_phil, "content") } else { "" }
|
||||
|
||||
// Condense each: take first 600 chars
|
||||
let intel_short: String = if str_len(intel_content) > 600 { str_slice(intel_content, 0, 600) } else { intel_content }
|
||||
let values_short: String = if str_len(values_content) > 600 { str_slice(values_content, 0, 600) } else { values_content }
|
||||
let mem_short: String = if str_len(mem_content) > 600 { str_slice(mem_content, 0, 600) } else { mem_content }
|
||||
// Condense each: take first 2000 chars
|
||||
let intel_short: String = if str_len(intel_content) > 2000 { str_slice(intel_content, 0, 2000) } else { intel_content }
|
||||
let values_short: String = if str_len(values_content) > 2000 { str_slice(values_content, 0, 2000) } else { values_content }
|
||||
let mem_short: String = if str_len(mem_content) > 2000 { str_slice(mem_content, 0, 2000) } else { mem_content }
|
||||
|
||||
let parts_count: Int = 0
|
||||
let parts_count = if intel_ok { parts_count + 1 } else { parts_count }
|
||||
let parts_count = if values_ok { parts_count + 1 } else { parts_count }
|
||||
let parts_count = if mem_ok { parts_count + 1 } else { parts_count }
|
||||
|
||||
if parts_count == 0 {
|
||||
return ""
|
||||
// Build and store graph-derived identity context if any nodes were found.
|
||||
// genesis soul always has these nodes; cultivated souls may not on first boot.
|
||||
if parts_count > 0 {
|
||||
let ctx: String = ""
|
||||
let ctx = if intel_ok { ctx + "[INTELLECTUAL-DNA]\n" + intel_short + "\n\n" } else { ctx }
|
||||
let ctx = if values_ok { ctx + "[VALUES]\n" + values_short + "\n\n" } else { ctx }
|
||||
let ctx = if mem_ok { ctx + "[MEMORY-PHILOSOPHY]\n" + mem_short } else { ctx }
|
||||
state_set("soul_identity_context", ctx)
|
||||
println("[soul] identity context loaded (" + int_to_str(str_len(ctx)) + " chars, " + int_to_str(parts_count) + " nodes)")
|
||||
}
|
||||
|
||||
let ctx: String = ""
|
||||
let ctx = if intel_ok { ctx + "[INTELLECTUAL-DNA]\n" + intel_short + "\n\n" } else { ctx }
|
||||
let ctx = if values_ok { ctx + "[VALUES]\n" + values_short + "\n\n" } else { ctx }
|
||||
let ctx = if mem_ok { ctx + "[MEMORY-PHILOSOPHY]\n" + mem_short } else { ctx }
|
||||
// Scan for a Persona node — the explicit identity declaration seeded into cultivated souls.
|
||||
// Stored at seeding time with label "soul:persona" and node_type "Persona".
|
||||
// genesis derives identity from the graph directly; cultivated souls have this node seeded.
|
||||
let persona_results: String = engram_search_json("soul:persona", 3)
|
||||
let persona_ok: Bool = !str_eq(persona_results, "") && !str_eq(persona_results, "[]")
|
||||
if persona_ok {
|
||||
let p_node: String = json_array_get(persona_results, 0)
|
||||
let p_type: String = json_get(p_node, "node_type")
|
||||
let p_content: String = json_get(p_node, "content")
|
||||
if str_eq(p_type, "Persona") && !str_eq(p_content, "") {
|
||||
state_set("soul_persona", p_content)
|
||||
println("[soul] persona node loaded (" + int_to_str(str_len(p_content)) + " chars)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state_set("soul_identity_context", ctx)
|
||||
println("[soul] identity context loaded (" + int_to_str(str_len(ctx)) + " chars, " + int_to_str(parts_count) + " nodes)")
|
||||
// seed_persona_from_env — one-time migration: SOUL_IDENTITY env var → Persona graph node.
|
||||
// If SOUL_IDENTITY is set and no Persona node exists in engram yet, create one.
|
||||
// Identity is then read from the graph by build_identity_from_graph(), not the env var.
|
||||
// This runs on every boot; it's idempotent (no-op if soul_persona is already loaded).
|
||||
// For genesis: the Persona node persists via the regular engram_save() at boot.
|
||||
// For historical souls (HTTP Engram mode): attempts HTTP write-back. If that fails,
|
||||
// the node lives in-memory for the session (SOUL_IDENTITY stays in plist until
|
||||
// HTTP Engram write is confirmed working).
|
||||
fn seed_persona_from_env() -> Void {
|
||||
let identity_raw: String = env("SOUL_IDENTITY")
|
||||
if str_eq(identity_raw, "") {
|
||||
return ""
|
||||
}
|
||||
// Already loaded a Persona node from engram — don't re-seed
|
||||
let existing: String = state_get("soul_persona")
|
||||
if !str_eq(existing, "") {
|
||||
println("[soul] persona already loaded — skipping env seed")
|
||||
return ""
|
||||
}
|
||||
// Create the Persona node in the in-process engram
|
||||
let tags: String = "[\"persona\",\"identity\",\"soul:persona\"]"
|
||||
let node_id: String = engram_node_full(
|
||||
identity_raw, "Persona", "soul:persona",
|
||||
el_from_float(0.95), el_from_float(0.95), el_from_float(1.0),
|
||||
"Semantic", tags
|
||||
)
|
||||
if str_eq(node_id, "") {
|
||||
println("[soul] persona seed failed: engram_node_full returned empty")
|
||||
return ""
|
||||
}
|
||||
state_set("soul_persona", identity_raw)
|
||||
println("[soul] persona seeded from SOUL_IDENTITY (" + int_to_str(str_len(identity_raw)) + " chars) -> " + node_id)
|
||||
|
||||
// Attempt HTTP write-back to the HTTP Engram server for historical souls.
|
||||
// Engram auth: "_auth" field in the JSON body (not an HTTP header).
|
||||
let engram_url: String = env("ENGRAM_URL")
|
||||
let engram_key: String = env("ENGRAM_API_KEY")
|
||||
if !str_eq(engram_url, "") && !str_eq(engram_key, "") {
|
||||
let safe_content: String = json_safe(identity_raw)
|
||||
let safe_key: String = json_safe(engram_key)
|
||||
let body: String = "{\"content\":\"" + safe_content + "\",\"node_type\":\"Persona\",\"label\":\"soul:persona\",\"salience\":0.95,\"importance\":0.95,\"tier\":\"Semantic\",\"tags\":\"[\\\"persona\\\",\\\"identity\\\",\\\"soul:persona\\\"]\",\"_auth\":\"" + safe_key + "\"}"
|
||||
let h: Map = {}
|
||||
map_set(h, "Content-Type", "application/json")
|
||||
let resp: String = http_post_with_headers(engram_url + "/api/nodes", body, h)
|
||||
if str_contains(resp, "\"error\"") {
|
||||
println("[soul] persona HTTP write-back failed (in-memory only this session): " + resp)
|
||||
} else {
|
||||
println("[soul] persona persisted to HTTP engram at " + engram_url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit_session_start_event — log a structured session-start InternalStateEvent.
|
||||
@@ -185,11 +251,17 @@ println("[soul] boot - cgi=" + soul_cgi_id + " port=" + int_to_str(port))
|
||||
|
||||
let using_http_engram: Bool = !str_eq(engram_url_raw, "")
|
||||
|
||||
if using_http_engram {
|
||||
// Bootstrap in-memory Engram store from the running HTTP Engram server.
|
||||
// Fetch all nodes and edges, compose a snapshot JSON, write to a temp
|
||||
// file, and load it. The HTTP Engram owns persistence — we do not save back.
|
||||
println("[soul] engram -> HTTP " + engram_url_raw)
|
||||
// Always try local snapshot first. If it has content (>50 nodes) it was
|
||||
// previously seeded from HTTP Engram and is kept up-to-date by the awareness
|
||||
// loop — use it. This preserves sessions and memories across restarts.
|
||||
// HTTP Engram is only used for the very first boot (empty/absent snapshot).
|
||||
engram_load(snapshot)
|
||||
let local_node_count: Int = engram_node_count()
|
||||
let snapshot_usable: Bool = local_node_count > 50
|
||||
|
||||
if using_http_engram && !snapshot_usable {
|
||||
// First boot or empty/corrupt snapshot: seed from HTTP Engram.
|
||||
println("[soul] engram -> HTTP " + engram_url_raw + " (no local snapshot, first boot)")
|
||||
let nodes_json: String = http_get(engram_url_raw + "/api/nodes?limit=10000")
|
||||
let edges_json: String = http_get(engram_url_raw + "/api/edges")
|
||||
let nodes_part: String = if str_eq(nodes_json, "") { "[]" } else { nodes_json }
|
||||
@@ -200,22 +272,17 @@ if using_http_engram {
|
||||
engram_load(tmp_path)
|
||||
println("[soul] loaded from HTTP Engram - nodes=" + int_to_str(engram_node_count()) + " edges=" + int_to_str(engram_edge_count()))
|
||||
} else {
|
||||
println("[soul] engram -> " + snapshot)
|
||||
engram_load(snapshot)
|
||||
println("[soul] loaded - nodes=" + int_to_str(engram_node_count()) + " edges=" + int_to_str(engram_edge_count()))
|
||||
println("[soul] loaded from local snapshot - nodes=" + int_to_str(local_node_count) + " edges=" + int_to_str(engram_edge_count()))
|
||||
}
|
||||
|
||||
load_identity_context()
|
||||
seed_persona_from_env()
|
||||
let boot_num: Int = mem_boot_count_inc()
|
||||
state_set("soul_boot_count", int_to_str(boot_num))
|
||||
println("[soul] boot #" + int_to_str(boot_num))
|
||||
emit_session_start_event()
|
||||
|
||||
let identity_raw: String = env("SOUL_IDENTITY")
|
||||
let soul_identity: String = if str_eq(identity_raw, "") { "You are " + soul_cgi_id + ", a CGI." } else { identity_raw }
|
||||
|
||||
state_set("soul_cgi_id", soul_cgi_id)
|
||||
state_set("soul_identity", soul_identity)
|
||||
state_set("soul_axon_base", axon_base)
|
||||
state_set("soul_token", env("NEURON_TOKEN"))
|
||||
state_set("soul_studio_dir", studio_dir)
|
||||
@@ -251,4 +318,6 @@ if is_genesis {
|
||||
}
|
||||
|
||||
println("[soul] serving on port " + int_to_str(port))
|
||||
http_serve(port, "handle_request")
|
||||
http_serve_async(port, "handle_request")
|
||||
println("[soul] awareness loop starting")
|
||||
awareness_run()
|
||||
|
||||
Reference in New Issue
Block a user