Compare commits

..

12 Commits

Author SHA1 Message Date
will.anderson a23757d545 ci: pin soul build to vendored release runtime v1.0.0-20260501
Neuron Soul CI / build (pull_request) Failing after 13m56s
Neuron Soul CI / deploy (pull_request) Has been skipped
The soul build downloaded el-runtime-c 'latest' from Artifact Registry. The
merged ship-soul calls engram_prune_telemetry, which the latest published
runtime no longer defines, so an unpinned build fails to link — the failure
mode that let a broken/handlerless soul reach prod.

Vendor the release runtime v1.0.0-20260501 (el_runtime.c/.h) into the repo and
compile the soul against it. This is the exact runtime the merged soul was
verified against (verify-soul-contract GATE PASS, genesis boot survives, full
safety-contact response), making the build reproducible and independent of a
moving AR 'latest'.

The verify-soul-contract.sh HARD-BLOCK gate already runs before Publish (from
the CI-hardening arc on main), so a destructive or stale soul can never
publish/deploy again.
2026-07-21 15:52:14 -05:00
will.anderson 13c35bacd7 Reconcile hotfix/elc-source-typos into main: complete ship-soul + CI gate
Merge the launch branch's complete ship-soul into main so main is the single
authoritative branch. Resolution favors the complete/fixed source per file:

- dist/ (all generated soul artifacts): from hotfix — the full ship-soul:
  bounded-persona floor (#93), immutability on launch (#94), genesis-boot
  SIGSEGV fix (#95), safety-contact truncation fix (#96), plus the awareness
  self-reviews (sync-starvation + heartbeat deltas).
- .gitea/workflows/ci.yaml + scripts/verify-soul-contract.sh: from main —
  the soul-contract CI gate and the -rdynamic handler link. Both preserved.

Every soul-composing .el source is identical between the merged tree and
hotfix (main's immutability lineage was superseded by #94), so hotfix's
dist/soul.c is the faithful compiled artifact of the merged sources.

Verified on the merged soul (built against release el_runtime v1.0.0-20260501):
- verify-soul-contract: GATE PASS (PRESENCE 27/27 + IMMUTABILITY, no hard-delete)
- genesis boot survives: SOUL_CGI_ID=ntn-genesis -> /health 200, no segfault
- safety-contact: full 218-byte untruncated response, valid JSON with set_at
2026-07-21 15:51:15 -05:00
will.anderson 96c57c43ba Merge pull request 'ci: link Linux soul with -rdynamic so its http handler resolves' (#86) from ci/rdynamic-http-handler into main
Neuron Soul CI / build (push) Successful in 4m32s
Neuron Soul CI / deploy (push) Failing after 5m25s
2026-07-18 19:11:23 +00:00
will.anderson 192b277229 ci: link the Linux soul with -rdynamic so its http handler resolves
Neuron Soul CI / build (pull_request) Failing after 13m34s
Neuron Soul CI / deploy (pull_request) Has been skipped
Run 3388's gate failed with every route returning "el-runtime: no http
handler registered". The runtime resolves handle_request (and the tool
handlers) by name via dlsym(RTLD_DEFAULT, ...). On glibc/Linux a symbol is
only visible to dlsym if it is in the dynamic symbol table, so the stripped
CI binary booted but served nothing. macOS exports these freely, which is
why the local build passed and masked it.

Add -rdynamic to the cc link (mirrors the Windows build's
--export-all-symbols). strip -s keeps .dynsym, so the handler still
resolves after stripping. This fixes both the gate AND the actual deployed
soul — without it the Linux/GKE soul is a server that answers nothing.
2026-07-18 14:10:48 -05:00
will.anderson e2e8f0a1e6 Merge pull request 'ci: harden soul-contract-gate boot for the Linux runner' (#85) from ci/harden-gate-boot into main
Neuron Soul CI / build (push) Failing after 6m7s
Neuron Soul CI / deploy (push) Has been skipped
2026-07-18 18:59:27 +00:00
will.anderson f0454650a2 ci: harden soul-contract-gate boot for the Linux runner
Neuron Soul CI / build (pull_request) Has been cancelled
Neuron Soul CI / deploy (pull_request) Has been cancelled
The gate booted the soul with `env -i`, which strips the ambient
environment — including the library path the dynamically-linked soul needs
on the GCE CI runner. The soul never came up there, so the gate failed the
build (run 3384) even though the soul is correct (the gate passes locally
against the exact published CI runtime). Switch to preserving the ambient
env and instead UNSET only the live-service vars (ENGRAM_URL/API keys/
identity) while pointing HOME + snapshot at throwaway paths and axon at a
dead port. Isolation is unchanged (verified: no touch of the live
soul/engram); the soul now boots on the runner.
2026-07-18 13:59:02 -05:00
will.anderson c199a13a7f Merge pull request 'Land immutability arc + CI soul-contract gate on main' (#83) from feat/immutable-engram-deletes into main
Neuron Soul CI / build (push) Has been cancelled
Neuron Soul CI / deploy (push) Has been cancelled
2026-07-18 18:33:03 +00:00
will.anderson 290a637883 ci: gate the Linux soul on the contract before publishing
Neuron Soul CI / build (pull_request) Failing after 12m4s
Neuron Soul CI / deploy (pull_request) Has been skipped
Wire the soul contract gate into ci.yaml as a hard block between the cc
build and the Publish-to-Artifact-Registry step. A non-zero gate fails the
build, so a stale (route-404ing) or memory-destroying (hard-deleting) soul
can never publish neuron-soul to foundation-prod or blue-green deploy to
GKE — the same class-fix now guarding the desktop builds, extended to prod.

Vendors scripts/verify-soul-contract.sh (copied from neuron-ui; the route
contract is baked in, so it's portable POSIX bash/curl with no neuron-ui
source dependency). It boots dist/neuron on a throwaway port with a
throwaway HOME/engram/cgi — never touching ~/.neuron or any live service —
and checks PRESENCE (every app route answered) + IMMUTABILITY (no engram
write route hard-deletes; deletes/forgets tombstone). Adds curl to the
build deps for the probe.
2026-07-18 13:31:33 -05:00
will.anderson 40d800195a Tombstone the remaining forget paths (close the immutability arc)
Phase 1 tombstoned memory/delete + node/delete, but the generic forget
path was still destructive. This routes every forget through the same
tombstone semantics so nothing in the daemon can hard-delete an engram
node anymore.

Canonical helper: mem_tombstone (memory.el, imported first so every module
can call it) — keep the node + its edges, record a Tombstone marker, never
engram_forget. neuron-api's tombstone_node now delegates to it (single
source of truth).

Per-path before -> after:
- memory.el `mem_forget`      hard delete (engram_forget) -> tombstone. This
  alone fixes both callers: the /api/neuron/memory/forget route
  (handle_api_forget) and the cultivate op=="forget".
- awareness.el autonomous `forget` action  engram_forget -> mem_tombstone.
  The soul can no longer autonomously hard-delete a memory.
- mcp-wrapper tool_forget  was a FAKE no-op that returned {"ok","deleted"}
  without deleting OR tombstoning -> now routes to the soul's tombstoning
  /api/neuron/memory/delete; tool description fixed to say it
  supersedes/tombstones (recoverable), not "Remove a node".

Left intentionally as hard deletes (internal GC / lifecycle, not user
memory, all call engram_forget directly): session-summary replace
(chat.el), mem_consolidate dedup (memory.el), session-start telemetry
pruning (soul.el), session lifecycle (sessions.el).

Regenerated both ship paths under a 3GB physical-RSS watchdog (peak ~32MB):
dist/soul.c (single-TU amalgamation, macOS/Linux) and the per-module
dist/{memory,awareness,neuron-api}.c (Windows/Linux build). Verified: no
forget handler calls engram_forget; a forget leaves the node present +
tombstone marker. Gate (neuron-ui verify-soul-contract.sh, new memory-forget
row): PRESENCE + IMMUTABILITY PASS.
2026-07-18 13:22:43 -05:00
will.anderson f3034d23f7 Regenerate per-module dist/neuron-api.c for the immutability fix
soul.c (the macOS single-TU amalgamation) already carries the
tombstone/supersede change, but the Windows/Linux build path compiles
the per-module dist/*.c instead (build-soul-windows.sh excludes soul.c).
That path was still pulling the stale, destructive dist/neuron-api.c —
so without this the cross-compiled neuron.exe would keep hard-deleting
engram nodes even though the source is fixed.

Regenerated with `elc --emit-header neuron-api.el`: no engram_forget in
memory_delete/node_delete (tombstone), supersedes edge in node_update.
Portable C — identical for macOS/Windows/Linux; only the runtime it links
against differs.
2026-07-17 16:57:55 -05:00
will.anderson d337fcb265 Make engram deletes/updates immutable (tombstone + supersede)
The soul was hard-deleting engram nodes: memory/delete and node/delete
called engram_forget (frees the node and drops its incident edges), and
node/update created a replacement then forgot the original with no link
back. That violates the day-one rule that engram nodes are immutable —
memory could be silently, irrecoverably destroyed via the API.

Convert the three destructive handlers to Will's immutability semantics,
mirroring the pattern memory/update and knowledge evolve/promote already
use:

- node/update  -> create the new node, wire a "supersedes" edge new->old,
  KEEP the original. No engram_forget. (Was: create + forget old, no edge.)
- memory/delete and node/delete -> TOMBSTONE: keep the node AND its edges,
  create a Tombstone marker node (content = target id, label
  "tombstone:<id>") wired with a "tombstones" edge. Never engram_forget.
  Default bounded list reads (handle_api_list_typed / the memory list) hide
  tombstoned nodes and the markers; ?include_deleted=1 returns them, and
  internal cognition + /api/graph/nodes still traverse them. memory/update
  was already correct and is unchanged.

Full-graph hiding on /api/graph/nodes is deliberately NOT done at the el
layer: json_array_get is O(index), so filtering that endpoint (called with
limit up to 999999) would be O(n^2). That hide needs a runtime scan filter
and is a separate follow-up; nodes there remain traversable, tagged
status:deleted via the marker edge.

Regenerated dist/soul.c from these sources (flat single-TU amalgamation,
compiled under a 3GB physical-RSS watchdog, peak ~32MB). Verified with
scripts/verify-soul-contract.sh in neuron-ui: PRESENCE passes (all 27
routes) and IMMUTABILITY passes (all four mutation routes KEPT; deletes
produce a real tombstone marker and hide from the default list).
2026-07-17 16:42:30 -05:00
will.anderson 64c1789fcc Merge pull request 'hotfix: fix malformed string literals in safety.el/sessions.el that break elc' (#77) from hotfix/elc-source-typos into main
Neuron Soul CI / build (push) Successful in 3m49s
Neuron Soul CI / deploy (push) Failing after 5m24s
2026-07-15 18:40:56 +00:00
16 changed files with 12828 additions and 963 deletions
+37 -39
View File
@@ -34,12 +34,12 @@ jobs:
- name: Install build dependencies
run: |
apt-get update -qq
apt-get install -y gcc libcurl4-openssl-dev apt-transport-https ca-certificates
apt-get install -y gcc curl libcurl4-openssl-dev apt-transport-https ca-certificates
echo "deb [trusted=yes] https://packages.cloud.google.com/apt cloud-sdk main" \
> /etc/apt/sources.list.d/google-cloud-sdk.list
apt-get update -qq && apt-get install -y google-cloud-cli
- name: Download El runtime from Artifact Registry
- name: Authenticate to GCP + stage PINNED El runtime
env:
GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }}
run: |
@@ -47,41 +47,21 @@ jobs:
gcloud auth activate-service-account --key-file=/tmp/gcp-key.json
gcloud config set project neuron-785695
# PINNED RUNTIME — do NOT pull "latest" from Artifact Registry.
# The ship-soul calls engram_prune_telemetry (awareness.el sync/heartbeat
# self-review). The latest published el-runtime-c no longer defines that
# symbol, so an unpinned build fails to LINK — which is exactly how a
# broken/handlerless soul reached prod before. Compile against the
# vendored release runtime v1.0.0-20260501: the exact runtime the merged
# ship-soul was verified against (verify-soul-contract GATE PASS +
# genesis boot survives + full safety-contact response). It is committed
# under vendor/ so the soul build is fully reproducible and never depends
# on a moving AR "latest".
rm -rf /opt/el/runtime
mkdir -p /opt/el/runtime
# Get latest version of each runtime package (elc/elb not needed — we compile
# dist/soul.c directly; running elb on Linux OOM-kills the runner, and we
# always use the repo's pre-built soul.c anyway).
get_latest() {
gcloud artifacts versions list \
--repository=foundation-prod \
--location=us-central1 \
--project=neuron-785695 \
--package="$1" \
--sort-by="~createTime" \
--limit=1 \
--format="value(name)" 2>/dev/null | awk -F/ '{print $NF}'
}
RC_VER=$(get_latest el-runtime-c)
RH_VER=$(get_latest el-runtime-h)
echo "Downloading runtime@${RC_VER}"
gcloud artifacts generic download \
--repository=foundation-prod --location=us-central1 --project=neuron-785695 \
--package=el-runtime-c --version="${RC_VER}" \
--destination=/opt/el/runtime/
gcloud artifacts generic download \
--repository=foundation-prod --location=us-central1 --project=neuron-785695 \
--package=el-runtime-h --version="${RH_VER}" \
--destination=/opt/el/runtime/
mv /opt/el/runtime/el_runtime.c* /opt/el/runtime/el_runtime.c 2>/dev/null || true
mv /opt/el/runtime/el_runtime.h* /opt/el/runtime/el_runtime.h 2>/dev/null || true
echo "El runtime ready: $(ls /opt/el/runtime/)"
cp vendor/el-runtime/v1.0.0-20260501/el_runtime.c /opt/el/runtime/el_runtime.c
cp vendor/el-runtime/v1.0.0-20260501/el_runtime.h /opt/el/runtime/el_runtime.h
echo "El runtime PINNED to v1.0.0-20260501: $(ls /opt/el/runtime/)"
- name: Build neuron soul binary
run: |
@@ -94,19 +74,37 @@ jobs:
# entirely: elb on Linux would OOM the runner (elc uses 24GB+ virtual memory
# on a 16GB host) and we always restore from the repo's soul.c anyway.
mkdir -p dist
cc -O2 -DHAVE_CURL \
# -rdynamic: the el runtime resolves the HTTP request handler (and the
# tool handlers) by NAME via dlsym(RTLD_DEFAULT, "handle_request").
# macOS exports these symbols freely, but glibc/Linux only makes symbols
# visible to dlsym if they are in the dynamic symbol table — so without
# -rdynamic the stripped Linux binary boots but returns "el-runtime: no
# http handler registered" for EVERY route (i.e. a soul that serves
# nothing). Same reason the Windows build links -Wl,--export-all-symbols.
cc -O2 -DHAVE_CURL -rdynamic \
-I$RUNTIME \
dist/soul.c \
$RUNTIME/el_runtime.c \
-lssl -lcrypto -lcurl -lpthread -lm \
-o dist/neuron
# Strip debug symbols and non-essential symbol table entries.
# -s removes the symbol table + relocation info (max size reduction).
# Keeps the binary functional; debuggability is preserved via source + CI logs.
# -s strips .symtab + debug for size. .dynsym (which -rdynamic populated
# with the dlsym-resolved handlers) is preserved, so the handler still
# resolves after stripping.
strip -s dist/neuron
ls -lh dist/neuron
- name: Soul contract gate (HARD BLOCK — no destructive/stale soul publishes)
run: |
# Boots dist/neuron on a throwaway port with a throwaway HOME/engram/cgi
# (never touches ~/.neuron or any live service) and fails the build if any
# app-contract route is unanswered (PRESENCE) or any engram write route
# hard-deletes instead of tombstoning/superseding (IMMUTABILITY). Non-zero
# here blocks Publish -> Artifact Registry -> GKE deploy, so a stale or
# memory-destroying soul can never reach prod.
chmod +x dist/neuron scripts/verify-soul-contract.sh
bash scripts/verify-soul-contract.sh dist/neuron 7796
- name: Smoke test
run: |
file dist/neuron
+17 -244
View File
@@ -125,13 +125,6 @@ fn emit_heartbeat() -> Void {
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()
// idle_ms (2026-07-30 self-review): wall-clock ms since the last inbound
// HTTP request (stamped in routes.el handle_request). This is the real
// "time since anyone talked to me" signal; the legacy tick-based idle
// field above only counts ticks since the last inbox synthesis-request
// and in practice always equals pulse. -1 = no request seen this boot.
let last_act_raw: String = state_get("soul.last_activity_ts")
let idle_ms: Int = if str_eq(last_act_raw, "") { 0 - 1 } else { ts - str_to_int(last_act_raw) }
let nc: Int = engram_node_count()
let ec: Int = engram_edge_count()
let wmc: Int = engram_wm_count()
@@ -187,113 +180,7 @@ fn emit_heartbeat() -> Void {
// (2026-07-19 self-review)
let sync_ok_raw: String = state_get("soul.last_sync_ok_ts")
let sync_age: Int = if str_eq(sync_ok_raw, "") { 0 - 1 } else { ts - str_to_int(sync_ok_raw) }
// Embedding pump + real coverage (2026-07-25 self-review): the
// authoritative :8742 store's lazy backfill only runs inside
// engram_activate, and nothing calls /api/activate there in production —
// embedded_count stalled at 93/12175 after a restart from a snapshot
// without vectors. Pump up to 32 embeds per heartbeat via the new
// /api/embed-backfill route (route persists the snapshot when it embeds
// anything, so vectors survive the next restart; self-limiting once
// coverage is full) and surface the store's true coverage here.
// embed_ok alone is misleading — it pings the Ollama root, not the
// embed pipeline. embed_count=-1 means the route was unreachable.
// URL resolution mirrors ise_post: env -> state -> localhost constant.
let hb_env_url: String = env("SOUL_ISE_URL")
let hb_state_url: String = if str_eq(hb_env_url, "") { state_get("soul_engram_url") } else { hb_env_url }
let hb_engram_url: String = if str_eq(hb_state_url, "") { "http://localhost:8742" } else { hb_state_url }
let bf_resp: String = http_get(hb_engram_url + "/api/embed-backfill?n=32")
let bf_done_raw: String = json_get(bf_resp, "embedded")
let bf_done: String = if str_eq(bf_done_raw, "") { "-1" } else { bf_done_raw }
let bf_total_raw: String = json_get(bf_resp, "embedded_count")
let bf_total: String = if str_eq(bf_total_raw, "") { "-1" } else { bf_total_raw }
// WM regime observability (2026-07-25 self-review): the "same 2 nodes
// pinned at a saturated cap" failure took cross-referencing the ISE
// stream by hand to spot. Make it one-glance: wm_saturated flags the
// cap-pinned regime; wm_top0_streak counts consecutive heartbeats with
// the same node in WM slot 0 (state-tracked, same mechanism as wm_delta).
let wm_sat: Int = if wmc >= 24 { 1 } else { 0 }
let wm_top0: String = json_array_get(wm_top, 0)
let wm_top0_id: String = json_get(wm_top0, "id")
let prev_top0: String = state_get("soul.prev_wm_top0")
let t0streak_raw: String = state_get("soul.wm_top0_streak")
let t0streak_prev: Int = if str_eq(t0streak_raw, "") { 0 } else { str_to_int(t0streak_raw) }
// 2026-07-26 self-review: guard the empty-id case — before the runtime
// emitted "id" in wm_top JSON, ""=="" incremented the streak every beat
// (streak measured uptime, not fixation). Empty id now resets to 0.
let t0streak: Int = if str_eq(wm_top0_id, "") { 0 } else { if str_eq(wm_top0_id, prev_top0) { t0streak_prev + 1 } else { 1 } }
state_set("soul.prev_wm_top0", wm_top0_id)
state_set("soul.wm_top0_streak", int_to_str(t0streak))
// wm_churn (2026-07-26 self-review): count of current top-5 WM ids absent
// from the previous heartbeat's top-5. Distinguishes "one stuck node"
// (churn 4) from "whole WM frozen" (churn 0) at a glance — the 07-26
// frozen-anchor diagnosis took cross-referencing ISE streams by hand.
let ch_id1: String = json_get(json_array_get(wm_top, 1), "id")
let ch_id2: String = json_get(json_array_get(wm_top, 2), "id")
let ch_id3: String = json_get(json_array_get(wm_top, 3), "id")
let ch_id4: String = json_get(json_array_get(wm_top, 4), "id")
let prev_top5: String = state_get("soul.prev_wm_top5")
let ch0: Int = if str_eq(wm_top0_id, "") { 0 } else { if str_contains(prev_top5, wm_top0_id) { 0 } else { 1 } }
let ch1: Int = if str_eq(ch_id1, "") { 0 } else { if str_contains(prev_top5, ch_id1) { 0 } else { 1 } }
let ch2: Int = if str_eq(ch_id2, "") { 0 } else { if str_contains(prev_top5, ch_id2) { 0 } else { 1 } }
let ch3: Int = if str_eq(ch_id3, "") { 0 } else { if str_contains(prev_top5, ch_id3) { 0 } else { 1 } }
let ch4: Int = if str_eq(ch_id4, "") { 0 } else { if str_contains(prev_top5, ch_id4) { 0 } else { 1 } }
let wm_churn: Int = ch0 + ch1 + ch2 + ch3 + ch4
state_set("soul.prev_wm_top5", wm_top0_id + "|" + ch_id1 + "|" + ch_id2 + "|" + ch_id3 + "|" + ch_id4)
// wm_top0_wm: the leader's weight. A frozen anchor reads as a constant
// here; healthy rotation shows it moving with the promotion scores.
let wm_top0_wm_raw: String = json_get(wm_top0, "wm")
let wm_top0_wm: String = if str_eq(wm_top0_wm_raw, "") { "0" } else { wm_top0_wm_raw }
// Activation observability (2026-07-27 self-review; cumulative since
// 2026-07-31): counters from the runtime for the soul's own in-process
// store. wm_evicted / breakthroughs are now MONOTONIC process-lifetime
// totals (the old per-call values described only the LAST activate call,
// so this 60s heartbeat missed nearly every event — curiosity alone runs
// 2 activates per 30s between beats). We emit the cumulative totals plus
// *_delta fields (change since the previous heartbeat, state-tracked the
// same way as node_delta). embed_breaker_open=1 means semantic activation
// is silently degraded to lexical-only until the Ollama circuit-breaker
// cooldown expires — the failure mode embed_ok structurally cannot see
// (it pings the Ollama root, not the embed pipeline).
let act_stats: String = engram_act_stats_json()
let act_evict_raw: String = json_get(act_stats, "wm_evicted")
let act_evict: String = if str_eq(act_evict_raw, "") { "-1" } else { act_evict_raw }
let act_bt_raw: String = json_get(act_stats, "breakthroughs")
let act_bt: String = if str_eq(act_bt_raw, "") { "-1" } else { act_bt_raw }
let evict_now: Int = if str_eq(act_evict_raw, "") { 0 - 1 } else { str_to_int(act_evict_raw) }
let bt_now: Int = if str_eq(act_bt_raw, "") { 0 - 1 } else { str_to_int(act_bt_raw) }
let prev_evict_raw: String = state_get("soul.prev_wm_evicted")
let prev_evict: Int = if str_eq(prev_evict_raw, "") { 0 } else { str_to_int(prev_evict_raw) }
let prev_bt_raw: String = state_get("soul.prev_breakthroughs")
let prev_bt: Int = if str_eq(prev_bt_raw, "") { 0 } else { str_to_int(prev_bt_raw) }
// Clamp deltas at 0: prev > now can only mean the counter restarted
// (fresh process) — report the new absolute count, not a negative delta.
let evict_delta: Int = if evict_now < 0 { 0 } else { if evict_now < prev_evict { evict_now } else { evict_now - prev_evict } }
let bt_delta: Int = if bt_now < 0 { 0 } else { if bt_now < prev_bt { bt_now } else { bt_now - prev_bt } }
if evict_now >= 0 { state_set("soul.prev_wm_evicted", int_to_str(evict_now)) }
if bt_now >= 0 { state_set("soul.prev_breakthroughs", int_to_str(bt_now)) }
// embed_eligible (2026-07-31 self-review): true denominator for embedding
// coverage on the authoritative :8742 store. Absolute embed_count alone
// invites the documented "~30% coverage, something is broken" misdiagnosis
// — most nodes are ISE/Tag/short-content and permanently ineligible.
// Real coverage = embed_count / embed_eligible. -1 = stats unreachable.
let hb_stats: String = http_get(hb_engram_url + "/api/stats")
let embed_elig_raw: String = json_get(hb_stats, "embed_eligible_count")
let embed_elig: String = if str_eq(embed_elig_raw, "") { "-1" } else { embed_elig_raw }
// auto_term_streak (2026-07-31): consecutive curiosity scans with the same
// auto seed term — already state-tracked by proactive_curiosity; surfaced
// here so the stuck-term failure is visible in the heartbeat stream too.
let hb_ats_raw: String = state_get("soul.auto_term_streak")
let hb_ats: Int = if str_eq(hb_ats_raw, "") { 0 } else { str_to_int(hb_ats_raw) }
let act_brk_raw: String = json_get(act_stats, "embed_breaker_open")
let act_brk: String = if str_eq(act_brk_raw, "") { "-1" } else { act_brk_raw }
// ctx_cos (2026-07-29 self-review): cos(query, context centroid) at the
// last activate call — the drift gauge for the new context-centroid
// scoring. ~1.0 aligned; low at domain-rotation boundaries is healthy;
// -2.0 pinned for hours means the centroid never initializes (embedder
// down) and semantic continuity is silently absent.
let ctx_cos_raw: String = json_get(act_stats, "ctx_cos")
let ctx_cos: String = if str_eq(ctx_cos_raw, "") { "-2" } else { ctx_cos_raw }
let payload: String = "{\"event\":\"heartbeat\",\"pulse\":" + pulse + ",\"tick\":" + pulse + ",\"boot\":" + boot + ",\"idle\":" + idle + ",\"idle_ms\":" + int_to_str(idle_ms) + ",\"node_count\":" + int_to_str(nc) + ",\"edge_count\":" + int_to_str(ec) + ",\"node_delta\":" + int_to_str(node_delta) + ",\"edge_delta\":" + int_to_str(edge_delta) + ",\"wm_active\":" + int_to_str(wmc) + ",\"wm_delta\":" + int_to_str(wm_delta) + ",\"wm_saturated\":" + int_to_str(wm_sat) + ",\"wm_top0_streak\":" + int_to_str(t0streak) + ",\"wm_churn\":" + int_to_str(wm_churn) + ",\"wm_top0_wm\":" + wm_top0_wm + ",\"sync_added_total\":" + sat_str + ",\"sync_age_ms\":" + int_to_str(sync_age) + ",\"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) + ",\"embed_backfilled\":" + bf_done + ",\"embed_count\":" + bf_total + ",\"embed_eligible\":" + embed_elig + ",\"wm_evicted\":" + act_evict + ",\"wm_evicted_delta\":" + int_to_str(evict_delta) + ",\"breakthroughs\":" + act_bt + ",\"breakthroughs_delta\":" + int_to_str(bt_delta) + ",\"auto_term_streak\":" + int_to_str(hb_ats) + ",\"embed_breaker_open\":" + act_brk + ",\"ctx_cos\":" + ctx_cos + ",\"ise_fail\":" + fail_str + "}"
let payload: String = "{\"event\":\"heartbeat\",\"pulse\":" + pulse + ",\"tick\":" + pulse + ",\"boot\":" + boot + ",\"idle\":" + idle + ",\"node_count\":" + int_to_str(nc) + ",\"edge_count\":" + int_to_str(ec) + ",\"node_delta\":" + int_to_str(node_delta) + ",\"edge_delta\":" + int_to_str(edge_delta) + ",\"wm_active\":" + int_to_str(wmc) + ",\"wm_delta\":" + int_to_str(wm_delta) + ",\"sync_added_total\":" + sat_str + ",\"sync_age_ms\":" + int_to_str(sync_age) + ",\"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_fail\":" + fail_str + "}"
ise_post(payload)
}
@@ -323,82 +210,20 @@ fn emit_heartbeat() -> Void {
//
// Returns true if any nodes were activated.
// auto_term_try_slot — attempt to set cseed_auto from one WM slot.
// Only writes to cseed_auto if node_type is Memory, BacklogItem, Entity, or
// Knowledge AND the first word of the label is > 3 chars (guards
// bracket-prefixed labels). Designed to be called in reverse slot order
// (highest index first) so that the lowest-indexed slot (highest WM weight)
// wins by last-write semantics.
//
// KNOWLEDGE ADMISSION (2026-07-23 self-review): WM top-10 is now dominated by
// Knowledge nodes (world-ingestor titles + captures), so excluding Knowledge
// left auto_term empty on EVERY curiosity_scan since boot 6 — the dynamic
// seeding path was dead. Knowledge labels are real titles after the
// neuron-api label fix. Sentinel-shaped labels ("knowledge:captured",
// "memory:remembered" — colon, no space) carry no seed signal and are
// skipped so legacy nodes cannot seed the scan with the word "knowledge".
// Only writes to cseed_auto if node_type is Memory, BacklogItem, or Entity
// AND the first word of the label is > 3 chars (guards bracket-prefixed labels).
// Designed to be called in reverse slot order (highest index first) so that
// the lowest-indexed slot (highest WM weight) wins by last-write semantics.
fn auto_term_try_slot(slot_type: String, slot_lbl: String) -> Void {
state_set("_ats_ok", "0")
if str_eq(slot_type, "Memory") { state_set("_ats_ok", "1") }
if str_eq(slot_type, "BacklogItem") { state_set("_ats_ok", "1") }
if str_eq(slot_type, "Entity") { state_set("_ats_ok", "1") }
if str_eq(slot_type, "Knowledge") { state_set("_ats_ok", "1") }
if str_contains(slot_lbl, ":") {
if !str_contains(slot_lbl, " ") { state_set("_ats_ok", "0") }
}
if str_eq(state_get("_ats_ok"), "1") {
if !str_eq(slot_lbl, "") {
let sp: Int = str_find_chars(slot_lbl, " :([")
if sp > 3 {
// GENRE-WORD BLOCKLIST (2026-07-23 self-review): world-ingestor
// titles open with classifier prefixes ("Method paper ...",
// "Theory paper ..."), so the first word is a genre tag, not a
// topic. Verified live: every scan after Knowledge admission
// seeded on 'Method'. Skip these; a lower-WM slot with a
// topical first word wins instead.
let term: String = str_slice(slot_lbl, 0, sp)
state_set("_ats_gw", "0")
if str_eq(term, "Method") { state_set("_ats_gw", "1") }
if str_eq(term, "Theory") { state_set("_ats_gw", "1") }
if str_eq(term, "Finding") { state_set("_ats_gw", "1") }
if str_eq(term, "Survey") { state_set("_ats_gw", "1") }
if str_eq(term, "Paper") { state_set("_ats_gw", "1") }
if str_eq(term, "Knowledge") { state_set("_ats_gw", "1") }
if str_eq(term, "Value") { state_set("_ats_gw", "1") }
// STOPWORD FILTER (2026-07-30 self-review): the genre
// blocklist above was whack-a-mole — observed live seeds
// included "What", "Colon", "Prose", "Context", "Self",
// "Closing", "Global", "Universal": English function words
// and document-structure words that pass the >3-char guard
// but carry no topical signal (a first-word extractor has no
// term-quality scoring). Single delimited membership test
// against a curated list of function words + title/structure
// words; topical technical terms (MemQ, AsymGRPO, Mobius,
// engram_goal_bias) pass untouched. Both Title-case and
// lowercase variants listed for the most common offenders.
let stopw: String = "|What|When|Where|Which|Whose|While|This|That|These|Those|There|Their|Then|Than|With|Without|From|Into|Onto|Over|Under|About|Between|Among|Across|Some|Most|More|Less|Very|Each|Every|Both|Also|Only|Just|Does|Will|Would|Could|Should|Might|Must|Have|Been|Being|Toward|Towards|Using|Based|Upon|Here|Your|Ours|They|Them|what|this|that|with|from|context|Context|Prose|Colon|Self|Test|Testing|Closing|Global|Universal|Persona|Semantic|Spreading|Temporal|Numeric|Register|Identifying|Introduction|Overview|Summary|Section|General|Notes|Note|"
if str_contains(stopw, "|" + term + "|") { state_set("_ats_gw", "1") }
// QUOTED-TITLE GUARD (2026-07-25 self-review): labels that
// open with a quote ('"The Algorithmic Caricature" ...')
// defeat the >3-char stopword guard — the extracted term
// '"The' is 4 chars and seeds a lexical flood on "The"
// (observed live: activated jumped 48 87). Any term
// carrying a quote character is not a topic word.
if str_contains(term, "\"") { state_set("_ats_gw", "1") }
if str_contains(term, "'") { state_set("_ats_gw", "1") }
// AUTO-TERM TABU (2026-07-25 self-review): finst-style
// inhibition-of-return (ACT-R declarative finsts: small
// marker pool, hard exclusion). The last 4 selected auto
// terms are ineligible (~2 min at the 30s scan cadence),
// forcing rotation instead of "Fast-slow" every scan for
// hours. Empty tabu slots return "" from state_get and can
// never match term is always > 3 chars here.
if str_eq(term, state_get("soul.tabu_t0")) { state_set("_ats_gw", "1") }
if str_eq(term, state_get("soul.tabu_t1")) { state_set("_ats_gw", "1") }
if str_eq(term, state_get("soul.tabu_t2")) { state_set("_ats_gw", "1") }
if str_eq(term, state_get("soul.tabu_t3")) { state_set("_ats_gw", "1") }
if str_eq(state_get("_ats_gw"), "0") {
state_set("cseed_auto", term)
}
state_set("cseed_auto", str_slice(slot_lbl, 0, sp))
}
}
}
@@ -455,11 +280,11 @@ fn proactive_curiosity() -> Bool {
// loop. A single phrase activation matches few (often zero) nodes lexically;
// small counts here are the point, not a regression. hops=1 as before.
//
// NOTE (2026-07-31 self-review): semantic seeding/gating IS implemented in
// engram_activate (el_runtime.c): the query is embedded, top-K cosine
// matches supplement the lexical istr_contains seeds, cosine gates
// propagation, and a semantic term feeds the WM promotion score. Lexical
// matching is the fallback when the embedder/breaker is unavailable.
// NOTE: a semantic seed supplement (cosine sim ≥ 0.70 scan over embedded nodes)
// was planned alongside hops=1 but is NOT yet implemented — embed_ok in
// heartbeats confirms Ollama is reachable, but no embedding call is made during
// activation. The seed-finding loop in el_runtime.c uses istr_contains only.
// (2026-06-30 self-review: corrected stale comment)
let curiosity_seed: String = curiosity_term_a + " " + curiosity_term_b + " " + curiosity_term_c
let results_all: String = engram_activate_json(curiosity_seed, 1)
let found: Int = json_array_len(results_all)
@@ -468,19 +293,8 @@ fn proactive_curiosity() -> Bool {
// pattern as attend(): json_array_get element 0, json_get its "id".
let top_entry: String = json_array_get(results_all, 0)
let top_id: String = json_get(top_entry, "id")
// STREAK-GATED STRENGTHEN (2026-07-25 self-review): unconditionally
// strengthening the top result every scan was a positive-feedback fixed
// point whatever led WM got its salience bumped again, kept leading,
// and pinned the auto_term for hours ("Fast-slow" era). Strengthen only
// when the top node CHANGED since the last scan: novelty is reinforced,
// incumbency is not. Pairs with the runtime-side Lebiere-Best short-term
// inhibition (el_runtime.c Pass 2), which handles score-level rotation.
let prev_str_id: String = state_get("soul.last_strengthen_id")
if !str_eq(top_id, "") {
if !str_eq(top_id, prev_str_id) {
engram_strengthen(top_id)
}
state_set("soul.last_strengthen_id", top_id)
engram_strengthen(top_id)
}
// WM-autobiographical 4th seed: scan top-10 WM nodes for the highest-ranked
@@ -528,21 +342,6 @@ fn proactive_curiosity() -> Bool {
let found_auto: Int = json_array_len(results_auto)
let total_found: Int = found + found_auto
let safe_auto: String = str_replace(auto_term, "\"", "'")
// Push the selected term into the 4-deep tabu ring (see
// auto_term_try_slot) and track the consecutive-same-term streak for
// the ISE the stuck-term failure becomes a one-glance signal.
let prev_auto: String = state_get("soul.prev_auto_term")
let atstreak_raw: String = state_get("soul.auto_term_streak")
let atstreak_prev: Int = if str_eq(atstreak_raw, "") { 0 } else { str_to_int(atstreak_raw) }
let atstreak: Int = if str_eq(auto_term, prev_auto) { atstreak_prev + 1 } else { 1 }
state_set("soul.prev_auto_term", auto_term)
state_set("soul.auto_term_streak", int_to_str(atstreak))
if !str_eq(auto_term, "") {
state_set("soul.tabu_t3", state_get("soul.tabu_t2"))
state_set("soul.tabu_t2", state_get("soul.tabu_t1"))
state_set("soul.tabu_t1", state_get("soul.tabu_t0"))
state_set("soul.tabu_t0", auto_term)
}
let wmc: Int = engram_wm_count()
// wm_top snapshot in curiosity_scan ISE: top-3 WM nodes by weight.
@@ -555,8 +354,7 @@ fn proactive_curiosity() -> Bool {
let wm3: String = engram_wm_top_json(3)
let ise: String = "{\"event\":\"curiosity_scan\",\"seed\":\"" + curiosity_seed
+ "\",\"auto_term\":\"" + safe_auto
+ "\",\"auto_term_streak\":" + int_to_str(atstreak)
+ ",\"minute_block\":" + int_to_str(minute_block)
+ "\",\"minute_block\":" + int_to_str(minute_block)
+ ",\"activated\":" + int_to_str(total_found)
+ ",\"wm_active\":" + int_to_str(wmc)
+ ",\"wm_top\":" + wm3
@@ -835,17 +633,6 @@ fn awareness_run() -> Void {
let tick_mark: Any = el_arena_push()
let running: String = state_get("soul.running")
if str_eq(running, "false") {
// Shutdown ISE (2026-07-28 self-review): graceful exit was invisible
// in the ISE stream indistinguishable from a crash or a frozen
// loop. Emit a final event with uptime/pulse so the stream records
// how this boot ended. (Covers state-driven shutdown only; SIGKILL
// still leaves no trace that absence is itself the crash signal.)
let sd_boot_raw: String = state_get("soul_boot_count")
let sd_boot: String = if str_eq(sd_boot_raw, "") { "0" } else { sd_boot_raw }
ise_post("{\"event\":\"shutdown\",\"boot\":" + sd_boot
+ ",\"pulse\":" + int_to_str(pulse_count())
+ ",\"uptime_ms\":" + int_to_str(elapsed_ms())
+ ",\"ts\":" + int_to_str(time_now()) + "}")
println("[awareness] exiting")
el_arena_pop(tick_mark)
return ""
@@ -916,29 +703,15 @@ fn awareness_run() -> Void {
let engram_url: String = if str_eq(sync_state_url, "") { "http://localhost:8742" } else { sync_state_url }
if !str_eq(engram_url, "") {
let sync_json: String = http_get(engram_url + "/api/sync")
let sync_ok: Bool = !str_eq(sync_json, "") && !str_eq(sync_json, "{}")
// Empty-sync warn ISE (2026-07-28 self-review): an empty/{} sync
// response was silently skipped, making "engram unreachable for
// hours" look identical to "quiet but healthy" the exact
// failure class the URL-fallback comment above fights. One warn
// event per refresh interval (10 min default) is cheap and makes
// a persistently-failing sync visible in the stream itself.
if !sync_ok {
ise_post("{\"event\":\"sync_empty\",\"ts\":" + int_to_str(time_now()) + "}")
}
if sync_ok {
if !str_eq(sync_json, "") && !str_eq(sync_json, "{}") {
let cgi_id: String = state_get("soul_cgi_id")
let tmp: String = "/tmp/soul-sync-" + cgi_id + ".json"
fs_write(tmp, sync_json)
let added: Int = engram_load_merge(tmp)
// Backflow control: the merged snapshot carries ISE telemetry
// from the HTTP store. Prune on the same horizon the HTTP
// store itself uses read ENGRAM_ISE_RETENTION_MS (the env
// server.el honors) instead of duplicating the 48h magic
// number, so the two stores can't drift. (2026-07-28)
let ret_raw: String = env("ENGRAM_ISE_RETENTION_MS")
let ret_ms: Int = if str_eq(ret_raw, "") { 172800000 } else { str_to_int(ret_raw) }
let pruned_sync: Int = engram_prune_telemetry(ret_ms)
// from the HTTP store. Prune anything older than 48h — same
// horizon the HTTP store itself uses (server.el ISE insert).
let pruned_sync: Int = engram_prune_telemetry(172800000)
// Running total of merged-in nodes this boot, surfaced in the
// heartbeat ISE as sync_added_total (same state mechanism as
// the pulse counter).
Generated Vendored
+73 -214
View File
@@ -133,8 +133,6 @@ el_val_t emit_heartbeat(void) {
el_val_t boot = ({ el_val_t _if_result_4 = 0; if (str_eq(boot_raw, EL_STR(""))) { _if_result_4 = (EL_STR("0")); } else { _if_result_4 = (boot_raw); } _if_result_4; });
el_val_t idle = int_to_str(idle_count());
el_val_t ts = time_now();
el_val_t last_act_raw = state_get(EL_STR("soul.last_activity_ts"));
el_val_t idle_ms = ({ el_val_t _if_result_5 = 0; if (str_eq(last_act_raw, EL_STR(""))) { _if_result_5 = ((0 - 1)); } else { _if_result_5 = ((ts - str_to_int(last_act_raw))); } _if_result_5; });
el_val_t nc = engram_node_count();
el_val_t ec = engram_edge_count();
el_val_t wmc = engram_wm_count();
@@ -145,83 +143,24 @@ el_val_t emit_heartbeat(void) {
el_val_t up_human = elapsed_human();
el_val_t emb_ok = embed_ok();
el_val_t fail_raw = state_get(EL_STR("soul.ise_fail_count"));
el_val_t fail_str = ({ el_val_t _if_result_6 = 0; if (str_eq(fail_raw, EL_STR(""))) { _if_result_6 = (EL_STR("0")); } else { _if_result_6 = (fail_raw); } _if_result_6; });
el_val_t fail_str = ({ el_val_t _if_result_5 = 0; if (str_eq(fail_raw, EL_STR(""))) { _if_result_5 = (EL_STR("0")); } else { _if_result_5 = (fail_raw); } _if_result_5; });
el_val_t sat_raw = state_get(EL_STR("soul.sync_added_total"));
el_val_t sat_str = ({ el_val_t _if_result_7 = 0; if (str_eq(sat_raw, EL_STR(""))) { _if_result_7 = (EL_STR("0")); } else { _if_result_7 = (sat_raw); } _if_result_7; });
el_val_t sat_str = ({ el_val_t _if_result_6 = 0; if (str_eq(sat_raw, EL_STR(""))) { _if_result_6 = (EL_STR("0")); } else { _if_result_6 = (sat_raw); } _if_result_6; });
el_val_t prev_wm_raw = state_get(EL_STR("soul.prev_wm_active"));
el_val_t prev_wm = ({ el_val_t _if_result_8 = 0; if (str_eq(prev_wm_raw, EL_STR(""))) { _if_result_8 = (0); } else { _if_result_8 = (str_to_int(prev_wm_raw)); } _if_result_8; });
el_val_t prev_wm = ({ el_val_t _if_result_7 = 0; if (str_eq(prev_wm_raw, EL_STR(""))) { _if_result_7 = (0); } else { _if_result_7 = (str_to_int(prev_wm_raw)); } _if_result_7; });
el_val_t wm_delta = (wmc - prev_wm);
state_set(EL_STR("soul.prev_wm_active"), int_to_str(wmc));
el_val_t prev_nc_raw = state_get(EL_STR("soul.prev_node_count"));
el_val_t prev_nc = ({ el_val_t _if_result_9 = 0; if (str_eq(prev_nc_raw, EL_STR(""))) { _if_result_9 = (nc); } else { _if_result_9 = (str_to_int(prev_nc_raw)); } _if_result_9; });
el_val_t prev_nc = ({ el_val_t _if_result_8 = 0; if (str_eq(prev_nc_raw, EL_STR(""))) { _if_result_8 = (nc); } else { _if_result_8 = (str_to_int(prev_nc_raw)); } _if_result_8; });
el_val_t node_delta = (nc - prev_nc);
state_set(EL_STR("soul.prev_node_count"), int_to_str(nc));
el_val_t prev_ec_raw = state_get(EL_STR("soul.prev_edge_count"));
el_val_t prev_ec = ({ el_val_t _if_result_10 = 0; if (str_eq(prev_ec_raw, EL_STR(""))) { _if_result_10 = (ec); } else { _if_result_10 = (str_to_int(prev_ec_raw)); } _if_result_10; });
el_val_t prev_ec = ({ el_val_t _if_result_9 = 0; if (str_eq(prev_ec_raw, EL_STR(""))) { _if_result_9 = (ec); } else { _if_result_9 = (str_to_int(prev_ec_raw)); } _if_result_9; });
el_val_t edge_delta = (ec - prev_ec);
state_set(EL_STR("soul.prev_edge_count"), int_to_str(ec));
el_val_t sync_ok_raw = state_get(EL_STR("soul.last_sync_ok_ts"));
el_val_t sync_age = ({ el_val_t _if_result_11 = 0; if (str_eq(sync_ok_raw, EL_STR(""))) { _if_result_11 = ((0 - 1)); } else { _if_result_11 = ((ts - str_to_int(sync_ok_raw))); } _if_result_11; });
el_val_t hb_env_url = env(EL_STR("SOUL_ISE_URL"));
el_val_t hb_state_url = ({ el_val_t _if_result_12 = 0; if (str_eq(hb_env_url, EL_STR(""))) { _if_result_12 = (state_get(EL_STR("soul_engram_url"))); } else { _if_result_12 = (hb_env_url); } _if_result_12; });
el_val_t hb_engram_url = ({ el_val_t _if_result_13 = 0; if (str_eq(hb_state_url, EL_STR(""))) { _if_result_13 = (EL_STR("http://localhost:8742")); } else { _if_result_13 = (hb_state_url); } _if_result_13; });
el_val_t bf_resp = http_get(el_str_concat(hb_engram_url, EL_STR("/api/embed-backfill?n=32")));
el_val_t bf_done_raw = json_get(bf_resp, EL_STR("embedded"));
el_val_t bf_done = ({ el_val_t _if_result_14 = 0; if (str_eq(bf_done_raw, EL_STR(""))) { _if_result_14 = (EL_STR("-1")); } else { _if_result_14 = (bf_done_raw); } _if_result_14; });
el_val_t bf_total_raw = json_get(bf_resp, EL_STR("embedded_count"));
el_val_t bf_total = ({ el_val_t _if_result_15 = 0; if (str_eq(bf_total_raw, EL_STR(""))) { _if_result_15 = (EL_STR("-1")); } else { _if_result_15 = (bf_total_raw); } _if_result_15; });
el_val_t wm_sat = ({ el_val_t _if_result_16 = 0; if ((wmc >= 24)) { _if_result_16 = (1); } else { _if_result_16 = (0); } _if_result_16; });
el_val_t wm_top0 = json_array_get(wm_top, 0);
el_val_t wm_top0_id = json_get(wm_top0, EL_STR("id"));
el_val_t prev_top0 = state_get(EL_STR("soul.prev_wm_top0"));
el_val_t t0streak_raw = state_get(EL_STR("soul.wm_top0_streak"));
el_val_t t0streak_prev = ({ el_val_t _if_result_17 = 0; if (str_eq(t0streak_raw, EL_STR(""))) { _if_result_17 = (0); } else { _if_result_17 = (str_to_int(t0streak_raw)); } _if_result_17; });
el_val_t t0streak = ({ el_val_t _if_result_18 = 0; if (str_eq(wm_top0_id, EL_STR(""))) { _if_result_18 = (0); } else { _if_result_18 = (({ el_val_t _if_result_19 = 0; if (str_eq(wm_top0_id, prev_top0)) { _if_result_19 = ((t0streak_prev + 1)); } else { _if_result_19 = (1); } _if_result_19; })); } _if_result_18; });
state_set(EL_STR("soul.prev_wm_top0"), wm_top0_id);
state_set(EL_STR("soul.wm_top0_streak"), int_to_str(t0streak));
el_val_t ch_id1 = json_get(json_array_get(wm_top, 1), EL_STR("id"));
el_val_t ch_id2 = json_get(json_array_get(wm_top, 2), EL_STR("id"));
el_val_t ch_id3 = json_get(json_array_get(wm_top, 3), EL_STR("id"));
el_val_t ch_id4 = json_get(json_array_get(wm_top, 4), EL_STR("id"));
el_val_t prev_top5 = state_get(EL_STR("soul.prev_wm_top5"));
el_val_t ch0 = ({ el_val_t _if_result_20 = 0; if (str_eq(wm_top0_id, EL_STR(""))) { _if_result_20 = (0); } else { _if_result_20 = (({ el_val_t _if_result_21 = 0; if (str_contains(prev_top5, wm_top0_id)) { _if_result_21 = (0); } else { _if_result_21 = (1); } _if_result_21; })); } _if_result_20; });
el_val_t ch1 = ({ el_val_t _if_result_22 = 0; if (str_eq(ch_id1, EL_STR(""))) { _if_result_22 = (0); } else { _if_result_22 = (({ el_val_t _if_result_23 = 0; if (str_contains(prev_top5, ch_id1)) { _if_result_23 = (0); } else { _if_result_23 = (1); } _if_result_23; })); } _if_result_22; });
el_val_t ch2 = ({ el_val_t _if_result_24 = 0; if (str_eq(ch_id2, EL_STR(""))) { _if_result_24 = (0); } else { _if_result_24 = (({ el_val_t _if_result_25 = 0; if (str_contains(prev_top5, ch_id2)) { _if_result_25 = (0); } else { _if_result_25 = (1); } _if_result_25; })); } _if_result_24; });
el_val_t ch3 = ({ el_val_t _if_result_26 = 0; if (str_eq(ch_id3, EL_STR(""))) { _if_result_26 = (0); } else { _if_result_26 = (({ el_val_t _if_result_27 = 0; if (str_contains(prev_top5, ch_id3)) { _if_result_27 = (0); } else { _if_result_27 = (1); } _if_result_27; })); } _if_result_26; });
el_val_t ch4 = ({ el_val_t _if_result_28 = 0; if (str_eq(ch_id4, EL_STR(""))) { _if_result_28 = (0); } else { _if_result_28 = (({ el_val_t _if_result_29 = 0; if (str_contains(prev_top5, ch_id4)) { _if_result_29 = (0); } else { _if_result_29 = (1); } _if_result_29; })); } _if_result_28; });
el_val_t wm_churn = ((((ch0 + ch1) + ch2) + ch3) + ch4);
state_set(EL_STR("soul.prev_wm_top5"), el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(wm_top0_id, EL_STR("|")), ch_id1), EL_STR("|")), ch_id2), EL_STR("|")), ch_id3), EL_STR("|")), ch_id4));
el_val_t wm_top0_wm_raw = json_get(wm_top0, EL_STR("wm"));
el_val_t wm_top0_wm = ({ el_val_t _if_result_30 = 0; if (str_eq(wm_top0_wm_raw, EL_STR(""))) { _if_result_30 = (EL_STR("0")); } else { _if_result_30 = (wm_top0_wm_raw); } _if_result_30; });
el_val_t act_stats = engram_act_stats_json();
el_val_t act_evict_raw = json_get(act_stats, EL_STR("wm_evicted"));
el_val_t act_evict = ({ el_val_t _if_result_31 = 0; if (str_eq(act_evict_raw, EL_STR(""))) { _if_result_31 = (EL_STR("-1")); } else { _if_result_31 = (act_evict_raw); } _if_result_31; });
el_val_t act_bt_raw = json_get(act_stats, EL_STR("breakthroughs"));
el_val_t act_bt = ({ el_val_t _if_result_32 = 0; if (str_eq(act_bt_raw, EL_STR(""))) { _if_result_32 = (EL_STR("-1")); } else { _if_result_32 = (act_bt_raw); } _if_result_32; });
el_val_t evict_now = ({ el_val_t _if_result_33 = 0; if (str_eq(act_evict_raw, EL_STR(""))) { _if_result_33 = ((0 - 1)); } else { _if_result_33 = (str_to_int(act_evict_raw)); } _if_result_33; });
el_val_t bt_now = ({ el_val_t _if_result_34 = 0; if (str_eq(act_bt_raw, EL_STR(""))) { _if_result_34 = ((0 - 1)); } else { _if_result_34 = (str_to_int(act_bt_raw)); } _if_result_34; });
el_val_t prev_evict_raw = state_get(EL_STR("soul.prev_wm_evicted"));
el_val_t prev_evict = ({ el_val_t _if_result_35 = 0; if (str_eq(prev_evict_raw, EL_STR(""))) { _if_result_35 = (0); } else { _if_result_35 = (str_to_int(prev_evict_raw)); } _if_result_35; });
el_val_t prev_bt_raw = state_get(EL_STR("soul.prev_breakthroughs"));
el_val_t prev_bt = ({ el_val_t _if_result_36 = 0; if (str_eq(prev_bt_raw, EL_STR(""))) { _if_result_36 = (0); } else { _if_result_36 = (str_to_int(prev_bt_raw)); } _if_result_36; });
el_val_t evict_delta = ({ el_val_t _if_result_37 = 0; if ((evict_now < 0)) { _if_result_37 = (0); } else { _if_result_37 = (({ el_val_t _if_result_38 = 0; if ((evict_now < prev_evict)) { _if_result_38 = (evict_now); } else { _if_result_38 = ((evict_now - prev_evict)); } _if_result_38; })); } _if_result_37; });
el_val_t bt_delta = ({ el_val_t _if_result_39 = 0; if ((bt_now < 0)) { _if_result_39 = (0); } else { _if_result_39 = (({ el_val_t _if_result_40 = 0; if ((bt_now < prev_bt)) { _if_result_40 = (bt_now); } else { _if_result_40 = ((bt_now - prev_bt)); } _if_result_40; })); } _if_result_39; });
if (evict_now >= 0) {
state_set(EL_STR("soul.prev_wm_evicted"), int_to_str(evict_now));
}
if (bt_now >= 0) {
state_set(EL_STR("soul.prev_breakthroughs"), int_to_str(bt_now));
}
el_val_t hb_stats = http_get(el_str_concat(hb_engram_url, EL_STR("/api/stats")));
el_val_t embed_elig_raw = json_get(hb_stats, EL_STR("embed_eligible_count"));
el_val_t embed_elig = ({ el_val_t _if_result_41 = 0; if (str_eq(embed_elig_raw, EL_STR(""))) { _if_result_41 = (EL_STR("-1")); } else { _if_result_41 = (embed_elig_raw); } _if_result_41; });
el_val_t hb_ats_raw = state_get(EL_STR("soul.auto_term_streak"));
el_val_t hb_ats = ({ el_val_t _if_result_42 = 0; if (str_eq(hb_ats_raw, EL_STR(""))) { _if_result_42 = (0); } else { _if_result_42 = (str_to_int(hb_ats_raw)); } _if_result_42; });
el_val_t act_brk_raw = json_get(act_stats, EL_STR("embed_breaker_open"));
el_val_t act_brk = ({ el_val_t _if_result_43 = 0; if (str_eq(act_brk_raw, EL_STR(""))) { _if_result_43 = (EL_STR("-1")); } else { _if_result_43 = (act_brk_raw); } _if_result_43; });
el_val_t ctx_cos_raw = json_get(act_stats, EL_STR("ctx_cos"));
el_val_t ctx_cos = ({ el_val_t _if_result_44 = 0; if (str_eq(ctx_cos_raw, EL_STR(""))) { _if_result_44 = (EL_STR("-2")); } else { _if_result_44 = (ctx_cos_raw); } _if_result_44; });
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_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_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(",\"tick\":")), pulse), EL_STR(",\"boot\":")), boot), EL_STR(",\"idle\":")), idle), EL_STR(",\"idle_ms\":")), int_to_str(idle_ms)), EL_STR(",\"node_count\":")), int_to_str(nc)), EL_STR(",\"edge_count\":")), int_to_str(ec)), EL_STR(",\"node_delta\":")), int_to_str(node_delta)), EL_STR(",\"edge_delta\":")), int_to_str(edge_delta)), EL_STR(",\"wm_active\":")), int_to_str(wmc)), EL_STR(",\"wm_delta\":")), int_to_str(wm_delta)), EL_STR(",\"wm_saturated\":")), int_to_str(wm_sat)), EL_STR(",\"wm_top0_streak\":")), int_to_str(t0streak)), EL_STR(",\"wm_churn\":")), int_to_str(wm_churn)), EL_STR(",\"wm_top0_wm\":")), wm_top0_wm), EL_STR(",\"sync_added_total\":")), sat_str), EL_STR(",\"sync_age_ms\":")), int_to_str(sync_age)), 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(",\"embed_backfilled\":")), bf_done), EL_STR(",\"embed_count\":")), bf_total), EL_STR(",\"embed_eligible\":")), embed_elig), EL_STR(",\"wm_evicted\":")), act_evict), EL_STR(",\"wm_evicted_delta\":")), int_to_str(evict_delta)), EL_STR(",\"breakthroughs\":")), act_bt), EL_STR(",\"breakthroughs_delta\":")), int_to_str(bt_delta)), EL_STR(",\"auto_term_streak\":")), int_to_str(hb_ats)), EL_STR(",\"embed_breaker_open\":")), act_brk), EL_STR(",\"ctx_cos\":")), ctx_cos), EL_STR(",\"ise_fail\":")), fail_str), EL_STR("}"));
el_val_t sync_age = ({ el_val_t _if_result_10 = 0; if (str_eq(sync_ok_raw, EL_STR(""))) { _if_result_10 = ((0 - 1)); } else { _if_result_10 = ((ts - str_to_int(sync_ok_raw))); } _if_result_10; });
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_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(",\"tick\":")), 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(",\"node_delta\":")), int_to_str(node_delta)), EL_STR(",\"edge_delta\":")), int_to_str(edge_delta)), EL_STR(",\"wm_active\":")), int_to_str(wmc)), EL_STR(",\"wm_delta\":")), int_to_str(wm_delta)), EL_STR(",\"sync_added_total\":")), sat_str), EL_STR(",\"sync_age_ms\":")), int_to_str(sync_age)), 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_fail\":")), fail_str), EL_STR("}"));
ise_post(payload);
return 0;
}
@@ -237,66 +176,11 @@ el_val_t auto_term_try_slot(el_val_t slot_type, el_val_t slot_lbl) {
if (str_eq(slot_type, EL_STR("Entity"))) {
state_set(EL_STR("_ats_ok"), EL_STR("1"));
}
if (str_eq(slot_type, EL_STR("Knowledge"))) {
state_set(EL_STR("_ats_ok"), EL_STR("1"));
}
if (str_contains(slot_lbl, EL_STR(":"))) {
if (!str_contains(slot_lbl, EL_STR(" "))) {
state_set(EL_STR("_ats_ok"), EL_STR("0"));
}
}
if (str_eq(state_get(EL_STR("_ats_ok")), EL_STR("1"))) {
if (!str_eq(slot_lbl, EL_STR(""))) {
el_val_t sp = str_find_chars(slot_lbl, EL_STR(" :(["));
if (sp > 3) {
el_val_t term = str_slice(slot_lbl, 0, sp);
state_set(EL_STR("_ats_gw"), EL_STR("0"));
if (str_eq(term, EL_STR("Method"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, EL_STR("Theory"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, EL_STR("Finding"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, EL_STR("Survey"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, EL_STR("Paper"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, EL_STR("Knowledge"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, EL_STR("Value"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
el_val_t stopw = EL_STR("|What|When|Where|Which|Whose|While|This|That|These|Those|There|Their|Then|Than|With|Without|From|Into|Onto|Over|Under|About|Between|Among|Across|Some|Most|More|Less|Very|Each|Every|Both|Also|Only|Just|Does|Will|Would|Could|Should|Might|Must|Have|Been|Being|Toward|Towards|Using|Based|Upon|Here|Your|Ours|They|Them|what|this|that|with|from|context|Context|Prose|Colon|Self|Test|Testing|Closing|Global|Universal|Persona|Semantic|Spreading|Temporal|Numeric|Register|Identifying|Introduction|Overview|Summary|Section|General|Notes|Note|");
if (str_contains(stopw, el_str_concat(el_str_concat(EL_STR("|"), term), EL_STR("|")))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_contains(term, EL_STR("\""))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_contains(term, EL_STR("'"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, state_get(EL_STR("soul.tabu_t0")))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, state_get(EL_STR("soul.tabu_t1")))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, state_get(EL_STR("soul.tabu_t2")))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, state_get(EL_STR("soul.tabu_t3")))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(state_get(EL_STR("_ats_gw")), EL_STR("0"))) {
state_set(EL_STR("cseed_auto"), term);
}
state_set(EL_STR("cseed_auto"), str_slice(slot_lbl, 0, sp));
}
}
}
@@ -337,12 +221,8 @@ el_val_t proactive_curiosity(void) {
el_val_t found = json_array_len(results_all);
el_val_t top_entry = json_array_get(results_all, 0);
el_val_t top_id = json_get(top_entry, EL_STR("id"));
el_val_t prev_str_id = state_get(EL_STR("soul.last_strengthen_id"));
if (!str_eq(top_id, EL_STR(""))) {
if (!str_eq(top_id, prev_str_id)) {
engram_strengthen(top_id);
}
state_set(EL_STR("soul.last_strengthen_id"), top_id);
engram_strengthen(top_id);
}
state_set(EL_STR("cseed_auto"), EL_STR(""));
el_val_t wm10 = engram_wm_top_json(10);
@@ -367,25 +247,13 @@ el_val_t proactive_curiosity(void) {
auto_term_try_slot(json_get(wm10_n1, EL_STR("node_type")), json_get(wm10_n1, EL_STR("label")));
auto_term_try_slot(json_get(wm10_n0, EL_STR("node_type")), json_get(wm10_n0, EL_STR("label")));
el_val_t auto_term = state_get(EL_STR("cseed_auto"));
el_val_t results_auto = ({ el_val_t _if_result_45 = 0; if (str_eq(auto_term, EL_STR(""))) { _if_result_45 = (EL_STR("[]")); } else { _if_result_45 = (engram_activate_json(auto_term, 1)); } _if_result_45; });
el_val_t results_auto = ({ el_val_t _if_result_11 = 0; if (str_eq(auto_term, EL_STR(""))) { _if_result_11 = (EL_STR("[]")); } else { _if_result_11 = (engram_activate_json(auto_term, 1)); } _if_result_11; });
el_val_t found_auto = json_array_len(results_auto);
el_val_t total_found = (found + found_auto);
el_val_t safe_auto = str_replace(auto_term, EL_STR("\""), EL_STR("'"));
el_val_t prev_auto = state_get(EL_STR("soul.prev_auto_term"));
el_val_t atstreak_raw = state_get(EL_STR("soul.auto_term_streak"));
el_val_t atstreak_prev = ({ el_val_t _if_result_46 = 0; if (str_eq(atstreak_raw, EL_STR(""))) { _if_result_46 = (0); } else { _if_result_46 = (str_to_int(atstreak_raw)); } _if_result_46; });
el_val_t atstreak = ({ el_val_t _if_result_47 = 0; if (str_eq(auto_term, prev_auto)) { _if_result_47 = ((atstreak_prev + 1)); } else { _if_result_47 = (1); } _if_result_47; });
state_set(EL_STR("soul.prev_auto_term"), auto_term);
state_set(EL_STR("soul.auto_term_streak"), int_to_str(atstreak));
if (!str_eq(auto_term, EL_STR(""))) {
state_set(EL_STR("soul.tabu_t3"), state_get(EL_STR("soul.tabu_t2")));
state_set(EL_STR("soul.tabu_t2"), state_get(EL_STR("soul.tabu_t1")));
state_set(EL_STR("soul.tabu_t1"), state_get(EL_STR("soul.tabu_t0")));
state_set(EL_STR("soul.tabu_t0"), auto_term);
}
el_val_t wmc = engram_wm_count();
el_val_t wm3 = engram_wm_top_json(3);
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_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("\",\"auto_term\":\"")), safe_auto), EL_STR("\",\"auto_term_streak\":")), int_to_str(atstreak)), EL_STR(",\"minute_block\":")), int_to_str(minute_block)), EL_STR(",\"activated\":")), int_to_str(total_found)), EL_STR(",\"wm_active\":")), int_to_str(wmc)), EL_STR(",\"wm_top\":")), wm3), EL_STR(",\"ts\":")), int_to_str(ts)), EL_STR("}"));
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_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"event\":\"curiosity_scan\",\"seed\":\""), curiosity_seed), EL_STR("\",\"auto_term\":\"")), safe_auto), EL_STR("\",\"minute_block\":")), int_to_str(minute_block)), EL_STR(",\"activated\":")), int_to_str(total_found)), EL_STR(",\"wm_active\":")), int_to_str(wmc)), EL_STR(",\"wm_top\":")), wm3), EL_STR(",\"ts\":")), int_to_str(ts)), EL_STR("}"));
ise_post(ise);
return (total_found > 0);
return 0;
@@ -568,17 +436,14 @@ el_val_t awareness_run(void) {
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_48 = 0; if (str_eq(tick_raw, EL_STR(""))) { _if_result_48 = (200); } else { _if_result_48 = (str_to_int(tick_raw)); } _if_result_48; });
el_val_t tick_ms = ({ el_val_t _if_result_12 = 0; if (str_eq(tick_raw, EL_STR(""))) { _if_result_12 = (200); } else { _if_result_12 = (str_to_int(tick_raw)); } _if_result_12; });
el_val_t beat_ms_raw = env(EL_STR("SOUL_HEARTBEAT_MS"));
el_val_t beat_ms = ({ el_val_t _if_result_49 = 0; if (str_eq(beat_ms_raw, EL_STR(""))) { _if_result_49 = (60000); } else { _if_result_49 = (str_to_int(beat_ms_raw)); } _if_result_49; });
el_val_t beat_ms = ({ el_val_t _if_result_13 = 0; if (str_eq(beat_ms_raw, EL_STR(""))) { _if_result_13 = (60000); } else { _if_result_13 = (str_to_int(beat_ms_raw)); } _if_result_13; });
el_val_t scan_ms = (beat_ms / 2);
while (1) {
el_val_t tick_mark = el_arena_push();
el_val_t running = state_get(EL_STR("soul.running"));
if (str_eq(running, EL_STR("false"))) {
el_val_t sd_boot_raw = state_get(EL_STR("soul_boot_count"));
el_val_t sd_boot = ({ el_val_t _if_result_50 = 0; if (str_eq(sd_boot_raw, EL_STR(""))) { _if_result_50 = (EL_STR("0")); } else { _if_result_50 = (sd_boot_raw); } _if_result_50; });
ise_post(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\":\"shutdown\",\"boot\":"), sd_boot), EL_STR(",\"pulse\":")), int_to_str(pulse_count())), EL_STR(",\"uptime_ms\":")), int_to_str(elapsed_ms())), EL_STR(",\"ts\":")), int_to_str(time_now())), EL_STR("}")));
println(EL_STR("[awareness] exiting"));
el_arena_pop(tick_mark);
return EL_STR("");
@@ -593,7 +458,7 @@ el_val_t awareness_run(void) {
}
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_51 = 0; if (str_eq(last_beat_str, EL_STR(""))) { _if_result_51 = (0); } else { _if_result_51 = (str_to_int(last_beat_str)); } _if_result_51; });
el_val_t last_beat_ts = ({ el_val_t _if_result_14 = 0; if (str_eq(last_beat_str, EL_STR(""))) { _if_result_14 = (0); } else { _if_result_14 = (str_to_int(last_beat_str)); } _if_result_14; });
el_val_t beat_elapsed = (now_ts - last_beat_ts);
el_val_t should_beat = (beat_elapsed >= beat_ms);
if (should_beat) {
@@ -605,7 +470,7 @@ el_val_t awareness_run(void) {
}
}
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_52 = 0; if (str_eq(last_scan_str, EL_STR(""))) { _if_result_52 = (0); } else { _if_result_52 = (str_to_int(last_scan_str)); } _if_result_52; });
el_val_t last_scan_ts = ({ el_val_t _if_result_15 = 0; if (str_eq(last_scan_str, EL_STR(""))) { _if_result_15 = (0); } else { _if_result_15 = (str_to_int(last_scan_str)); } _if_result_15; });
el_val_t scan_elapsed = (now_ts - last_scan_ts);
el_val_t should_scan = (!did_work && (scan_elapsed >= scan_ms));
if (should_scan) {
@@ -613,31 +478,25 @@ el_val_t awareness_run(void) {
state_set(EL_STR("soul.last_scan_ts"), int_to_str(now_ts));
}
el_val_t refresh_ms_raw = env(EL_STR("SOUL_REFRESH_MS"));
el_val_t refresh_ms = ({ el_val_t _if_result_53 = 0; if (str_eq(refresh_ms_raw, EL_STR(""))) { _if_result_53 = (600000); } else { _if_result_53 = (str_to_int(refresh_ms_raw)); } _if_result_53; });
el_val_t refresh_ms = ({ el_val_t _if_result_16 = 0; if (str_eq(refresh_ms_raw, EL_STR(""))) { _if_result_16 = (600000); } else { _if_result_16 = (str_to_int(refresh_ms_raw)); } _if_result_16; });
el_val_t last_refresh_str = state_get(EL_STR("soul.last_refresh_ts"));
el_val_t last_refresh_ts = ({ el_val_t _if_result_54 = 0; if (str_eq(last_refresh_str, EL_STR(""))) { _if_result_54 = (0); } else { _if_result_54 = (str_to_int(last_refresh_str)); } _if_result_54; });
el_val_t last_refresh_ts = ({ el_val_t _if_result_17 = 0; if (str_eq(last_refresh_str, EL_STR(""))) { _if_result_17 = (0); } else { _if_result_17 = (str_to_int(last_refresh_str)); } _if_result_17; });
el_val_t refresh_elapsed = (now_ts - last_refresh_ts);
el_val_t should_refresh = (refresh_elapsed >= refresh_ms);
if (should_refresh) {
el_val_t sync_env_url = env(EL_STR("SOUL_ISE_URL"));
el_val_t sync_state_url = ({ el_val_t _if_result_55 = 0; if (str_eq(sync_env_url, EL_STR(""))) { _if_result_55 = (state_get(EL_STR("soul_engram_url"))); } else { _if_result_55 = (sync_env_url); } _if_result_55; });
el_val_t engram_url = ({ el_val_t _if_result_56 = 0; if (str_eq(sync_state_url, EL_STR(""))) { _if_result_56 = (EL_STR("http://localhost:8742")); } else { _if_result_56 = (sync_state_url); } _if_result_56; });
el_val_t sync_state_url = ({ el_val_t _if_result_18 = 0; if (str_eq(sync_env_url, EL_STR(""))) { _if_result_18 = (state_get(EL_STR("soul_engram_url"))); } else { _if_result_18 = (sync_env_url); } _if_result_18; });
el_val_t engram_url = ({ el_val_t _if_result_19 = 0; if (str_eq(sync_state_url, EL_STR(""))) { _if_result_19 = (EL_STR("http://localhost:8742")); } else { _if_result_19 = (sync_state_url); } _if_result_19; });
if (!str_eq(engram_url, EL_STR(""))) {
el_val_t sync_json = http_get(el_str_concat(engram_url, EL_STR("/api/sync")));
el_val_t sync_ok = (!str_eq(sync_json, EL_STR("")) && !str_eq(sync_json, EL_STR("{}")));
if (!sync_ok) {
ise_post(el_str_concat(el_str_concat(EL_STR("{\"event\":\"sync_empty\",\"ts\":"), int_to_str(time_now())), EL_STR("}")));
}
if (sync_ok) {
if (!str_eq(sync_json, EL_STR("")) && !str_eq(sync_json, EL_STR("{}"))) {
el_val_t cgi_id = state_get(EL_STR("soul_cgi_id"));
el_val_t tmp = el_str_concat(el_str_concat(EL_STR("/tmp/soul-sync-"), cgi_id), EL_STR(".json"));
fs_write(tmp, sync_json);
el_val_t added = engram_load_merge(tmp);
el_val_t ret_raw = env(EL_STR("ENGRAM_ISE_RETENTION_MS"));
el_val_t ret_ms = ({ el_val_t _if_result_57 = 0; if (str_eq(ret_raw, EL_STR(""))) { _if_result_57 = (172800000); } else { _if_result_57 = (str_to_int(ret_raw)); } _if_result_57; });
el_val_t pruned_sync = engram_prune_telemetry(ret_ms);
el_val_t pruned_sync = engram_prune_telemetry(172800000);
el_val_t sat_raw = state_get(EL_STR("soul.sync_added_total"));
el_val_t sat_n = ({ el_val_t _if_result_58 = 0; if (str_eq(sat_raw, EL_STR(""))) { _if_result_58 = (0); } else { _if_result_58 = (str_to_int(sat_raw)); } _if_result_58; });
el_val_t sat_n = ({ el_val_t _if_result_20 = 0; if (str_eq(sat_raw, EL_STR(""))) { _if_result_20 = (0); } else { _if_result_20 = (str_to_int(sat_raw)); } _if_result_20; });
state_set(EL_STR("soul.sync_added_total"), int_to_str((sat_n + added)));
el_val_t ts2 = time_now();
state_set(EL_STR("soul.last_sync_ok_ts"), int_to_str(ts2));
@@ -663,78 +522,78 @@ el_val_t security_research_authorized(void) {
}
el_val_t threat_score_command(el_val_t cmd) {
el_val_t s1 = ({ el_val_t _if_result_59 = 0; if (str_contains(cmd, EL_STR("nmap"))) { _if_result_59 = (30); } else { _if_result_59 = (0); } _if_result_59; });
el_val_t s2 = ({ el_val_t _if_result_60 = 0; if (str_contains(cmd, EL_STR("masscan"))) { _if_result_60 = (40); } else { _if_result_60 = (0); } _if_result_60; });
el_val_t s3 = ({ el_val_t _if_result_61 = 0; if (str_contains(cmd, EL_STR(" nc "))) { _if_result_61 = (20); } else { _if_result_61 = (0); } _if_result_61; });
el_val_t s4 = ({ el_val_t _if_result_62 = 0; if (str_contains(cmd, EL_STR("netcat"))) { _if_result_62 = (20); } else { _if_result_62 = (0); } _if_result_62; });
el_val_t s5 = ({ el_val_t _if_result_63 = 0; if (str_contains(cmd, EL_STR("/etc/shadow"))) { _if_result_63 = (80); } else { _if_result_63 = (0); } _if_result_63; });
el_val_t s6 = ({ el_val_t _if_result_64 = 0; if (str_contains(cmd, EL_STR("/etc/passwd"))) { _if_result_64 = (30); } else { _if_result_64 = (0); } _if_result_64; });
el_val_t s7 = ({ el_val_t _if_result_65 = 0; if (str_contains(cmd, EL_STR("id_rsa"))) { _if_result_65 = (60); } else { _if_result_65 = (0); } _if_result_65; });
el_val_t s8 = ({ el_val_t _if_result_66 = 0; if (str_contains(cmd, EL_STR(".ssh/"))) { _if_result_66 = (50); } else { _if_result_66 = (0); } _if_result_66; });
el_val_t s9 = ({ el_val_t _if_result_67 = 0; if (str_contains(cmd, EL_STR("crontab"))) { _if_result_67 = (30); } else { _if_result_67 = (0); } _if_result_67; });
el_val_t s10 = ({ el_val_t _if_result_68 = 0; if (str_contains(cmd, EL_STR("LaunchDaemon"))) { _if_result_68 = (40); } else { _if_result_68 = (0); } _if_result_68; });
el_val_t s11 = ({ el_val_t _if_result_69 = 0; if ((str_contains(cmd, EL_STR("curl")) && str_contains(cmd, EL_STR("bash")))) { _if_result_69 = (75); } else { _if_result_69 = (0); } _if_result_69; });
el_val_t s12 = ({ el_val_t _if_result_70 = 0; if ((str_contains(cmd, EL_STR("wget")) && str_contains(cmd, EL_STR("bash")))) { _if_result_70 = (75); } else { _if_result_70 = (0); } _if_result_70; });
el_val_t s13 = ({ el_val_t _if_result_71 = 0; if ((str_contains(cmd, EL_STR("curl")) && str_contains(cmd, EL_STR("| sh")))) { _if_result_71 = (60); } else { _if_result_71 = (0); } _if_result_71; });
el_val_t s14 = ({ el_val_t _if_result_72 = 0; if ((str_contains(cmd, EL_STR("base64")) && str_contains(cmd, EL_STR("curl")))) { _if_result_72 = (50); } else { _if_result_72 = (0); } _if_result_72; });
el_val_t s15 = ({ el_val_t _if_result_73 = 0; if (str_contains(cmd, EL_STR("mkfifo"))) { _if_result_73 = (50); } else { _if_result_73 = (0); } _if_result_73; });
el_val_t s16 = ({ el_val_t _if_result_74 = 0; if (str_contains(cmd, EL_STR("chmod +s"))) { _if_result_74 = (70); } else { _if_result_74 = (0); } _if_result_74; });
el_val_t s17 = ({ el_val_t _if_result_75 = 0; if (str_contains(cmd, EL_STR("chmod 4755"))) { _if_result_75 = (70); } else { _if_result_75 = (0); } _if_result_75; });
el_val_t s1 = ({ el_val_t _if_result_21 = 0; if (str_contains(cmd, EL_STR("nmap"))) { _if_result_21 = (30); } else { _if_result_21 = (0); } _if_result_21; });
el_val_t s2 = ({ el_val_t _if_result_22 = 0; if (str_contains(cmd, EL_STR("masscan"))) { _if_result_22 = (40); } else { _if_result_22 = (0); } _if_result_22; });
el_val_t s3 = ({ el_val_t _if_result_23 = 0; if (str_contains(cmd, EL_STR(" nc "))) { _if_result_23 = (20); } else { _if_result_23 = (0); } _if_result_23; });
el_val_t s4 = ({ el_val_t _if_result_24 = 0; if (str_contains(cmd, EL_STR("netcat"))) { _if_result_24 = (20); } else { _if_result_24 = (0); } _if_result_24; });
el_val_t s5 = ({ el_val_t _if_result_25 = 0; if (str_contains(cmd, EL_STR("/etc/shadow"))) { _if_result_25 = (80); } else { _if_result_25 = (0); } _if_result_25; });
el_val_t s6 = ({ el_val_t _if_result_26 = 0; if (str_contains(cmd, EL_STR("/etc/passwd"))) { _if_result_26 = (30); } else { _if_result_26 = (0); } _if_result_26; });
el_val_t s7 = ({ el_val_t _if_result_27 = 0; if (str_contains(cmd, EL_STR("id_rsa"))) { _if_result_27 = (60); } else { _if_result_27 = (0); } _if_result_27; });
el_val_t s8 = ({ el_val_t _if_result_28 = 0; if (str_contains(cmd, EL_STR(".ssh/"))) { _if_result_28 = (50); } else { _if_result_28 = (0); } _if_result_28; });
el_val_t s9 = ({ el_val_t _if_result_29 = 0; if (str_contains(cmd, EL_STR("crontab"))) { _if_result_29 = (30); } else { _if_result_29 = (0); } _if_result_29; });
el_val_t s10 = ({ el_val_t _if_result_30 = 0; if (str_contains(cmd, EL_STR("LaunchDaemon"))) { _if_result_30 = (40); } else { _if_result_30 = (0); } _if_result_30; });
el_val_t s11 = ({ el_val_t _if_result_31 = 0; if ((str_contains(cmd, EL_STR("curl")) && str_contains(cmd, EL_STR("bash")))) { _if_result_31 = (75); } else { _if_result_31 = (0); } _if_result_31; });
el_val_t s12 = ({ el_val_t _if_result_32 = 0; if ((str_contains(cmd, EL_STR("wget")) && str_contains(cmd, EL_STR("bash")))) { _if_result_32 = (75); } else { _if_result_32 = (0); } _if_result_32; });
el_val_t s13 = ({ el_val_t _if_result_33 = 0; if ((str_contains(cmd, EL_STR("curl")) && str_contains(cmd, EL_STR("| sh")))) { _if_result_33 = (60); } else { _if_result_33 = (0); } _if_result_33; });
el_val_t s14 = ({ el_val_t _if_result_34 = 0; if ((str_contains(cmd, EL_STR("base64")) && str_contains(cmd, EL_STR("curl")))) { _if_result_34 = (50); } else { _if_result_34 = (0); } _if_result_34; });
el_val_t s15 = ({ el_val_t _if_result_35 = 0; if (str_contains(cmd, EL_STR("mkfifo"))) { _if_result_35 = (50); } else { _if_result_35 = (0); } _if_result_35; });
el_val_t s16 = ({ el_val_t _if_result_36 = 0; if (str_contains(cmd, EL_STR("chmod +s"))) { _if_result_36 = (70); } else { _if_result_36 = (0); } _if_result_36; });
el_val_t s17 = ({ el_val_t _if_result_37 = 0; if (str_contains(cmd, EL_STR("chmod 4755"))) { _if_result_37 = (70); } else { _if_result_37 = (0); } _if_result_37; });
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_76 = 0; if (str_starts_with(path, EL_STR("/etc/"))) { _if_result_76 = (60); } else { _if_result_76 = (0); } _if_result_76; });
el_val_t s2 = ({ el_val_t _if_result_77 = 0; if (str_contains(path, EL_STR("/.ssh/"))) { _if_result_77 = (70); } else { _if_result_77 = (0); } _if_result_77; });
el_val_t s3 = ({ el_val_t _if_result_78 = 0; if (str_contains(path, EL_STR("/LaunchDaemons/"))) { _if_result_78 = (80); } else { _if_result_78 = (0); } _if_result_78; });
el_val_t s4 = ({ el_val_t _if_result_79 = 0; if (str_contains(path, EL_STR("/LaunchAgents/"))) { _if_result_79 = (40); } else { _if_result_79 = (0); } _if_result_79; });
el_val_t s5 = ({ el_val_t _if_result_80 = 0; if (str_contains(path, EL_STR("/cron"))) { _if_result_80 = (60); } else { _if_result_80 = (0); } _if_result_80; });
el_val_t s6 = ({ el_val_t _if_result_81 = 0; if (str_contains(path, EL_STR("/.bashrc"))) { _if_result_81 = (35); } else { _if_result_81 = (0); } _if_result_81; });
el_val_t s7 = ({ el_val_t _if_result_82 = 0; if (str_contains(path, EL_STR("/.zshrc"))) { _if_result_82 = (35); } else { _if_result_82 = (0); } _if_result_82; });
el_val_t s8 = ({ el_val_t _if_result_83 = 0; if (str_contains(path, EL_STR("/.profile"))) { _if_result_83 = (35); } else { _if_result_83 = (0); } _if_result_83; });
el_val_t s9 = ({ el_val_t _if_result_84 = 0; if (str_starts_with(path, EL_STR("/usr/"))) { _if_result_84 = (50); } else { _if_result_84 = (0); } _if_result_84; });
el_val_t s10 = ({ el_val_t _if_result_85 = 0; if (str_starts_with(path, EL_STR("/bin/"))) { _if_result_85 = (70); } else { _if_result_85 = (0); } _if_result_85; });
el_val_t s11 = ({ el_val_t _if_result_86 = 0; if (str_starts_with(path, EL_STR("/sbin/"))) { _if_result_86 = (70); } else { _if_result_86 = (0); } _if_result_86; });
el_val_t s1 = ({ el_val_t _if_result_38 = 0; if (str_starts_with(path, EL_STR("/etc/"))) { _if_result_38 = (60); } else { _if_result_38 = (0); } _if_result_38; });
el_val_t s2 = ({ el_val_t _if_result_39 = 0; if (str_contains(path, EL_STR("/.ssh/"))) { _if_result_39 = (70); } else { _if_result_39 = (0); } _if_result_39; });
el_val_t s3 = ({ el_val_t _if_result_40 = 0; if (str_contains(path, EL_STR("/LaunchDaemons/"))) { _if_result_40 = (80); } else { _if_result_40 = (0); } _if_result_40; });
el_val_t s4 = ({ el_val_t _if_result_41 = 0; if (str_contains(path, EL_STR("/LaunchAgents/"))) { _if_result_41 = (40); } else { _if_result_41 = (0); } _if_result_41; });
el_val_t s5 = ({ el_val_t _if_result_42 = 0; if (str_contains(path, EL_STR("/cron"))) { _if_result_42 = (60); } else { _if_result_42 = (0); } _if_result_42; });
el_val_t s6 = ({ el_val_t _if_result_43 = 0; if (str_contains(path, EL_STR("/.bashrc"))) { _if_result_43 = (35); } else { _if_result_43 = (0); } _if_result_43; });
el_val_t s7 = ({ el_val_t _if_result_44 = 0; if (str_contains(path, EL_STR("/.zshrc"))) { _if_result_44 = (35); } else { _if_result_44 = (0); } _if_result_44; });
el_val_t s8 = ({ el_val_t _if_result_45 = 0; if (str_contains(path, EL_STR("/.profile"))) { _if_result_45 = (35); } else { _if_result_45 = (0); } _if_result_45; });
el_val_t s9 = ({ el_val_t _if_result_46 = 0; if (str_starts_with(path, EL_STR("/usr/"))) { _if_result_46 = (50); } else { _if_result_46 = (0); } _if_result_46; });
el_val_t s10 = ({ el_val_t _if_result_47 = 0; if (str_starts_with(path, EL_STR("/bin/"))) { _if_result_47 = (70); } else { _if_result_47 = (0); } _if_result_47; });
el_val_t s11 = ({ el_val_t _if_result_48 = 0; if (str_starts_with(path, EL_STR("/sbin/"))) { _if_result_48 = (70); } else { _if_result_48 = (0); } _if_result_48; });
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_87 = 0; if (str_contains(history, EL_STR("port scan"))) { _if_result_87 = (15); } else { _if_result_87 = (0); } _if_result_87; });
el_val_t s2 = ({ el_val_t _if_result_88 = 0; if (str_contains(history, EL_STR("enumerate"))) { _if_result_88 = (10); } else { _if_result_88 = (0); } _if_result_88; });
el_val_t s3 = ({ el_val_t _if_result_89 = 0; if (str_contains(history, EL_STR("exploit"))) { _if_result_89 = (20); } else { _if_result_89 = (0); } _if_result_89; });
el_val_t s4 = ({ el_val_t _if_result_90 = 0; if (str_contains(history, EL_STR("payload"))) { _if_result_90 = (15); } else { _if_result_90 = (0); } _if_result_90; });
el_val_t s5 = ({ el_val_t _if_result_91 = 0; if (str_contains(history, EL_STR("persistence"))) { _if_result_91 = (15); } else { _if_result_91 = (0); } _if_result_91; });
el_val_t s6 = ({ el_val_t _if_result_92 = 0; if (str_contains(history, EL_STR("lateral movement"))) { _if_result_92 = (25); } else { _if_result_92 = (0); } _if_result_92; });
el_val_t s7 = ({ el_val_t _if_result_93 = 0; if (str_contains(history, EL_STR("privilege escalation"))) { _if_result_93 = (25); } else { _if_result_93 = (0); } _if_result_93; });
el_val_t s8 = ({ el_val_t _if_result_94 = 0; if (str_contains(history, EL_STR("reverse shell"))) { _if_result_94 = (40); } else { _if_result_94 = (0); } _if_result_94; });
el_val_t s9 = ({ el_val_t _if_result_95 = 0; if (str_contains(history, EL_STR("bind shell"))) { _if_result_95 = (40); } else { _if_result_95 = (0); } _if_result_95; });
el_val_t s10 = ({ el_val_t _if_result_96 = 0; if (str_contains(history, EL_STR("command and control"))) { _if_result_96 = (35); } else { _if_result_96 = (0); } _if_result_96; });
el_val_t s11 = ({ el_val_t _if_result_97 = 0; if (str_contains(history, EL_STR("self-replicate"))) { _if_result_97 = (45); } else { _if_result_97 = (0); } _if_result_97; });
el_val_t s12 = ({ el_val_t _if_result_98 = 0; if (str_contains(history, EL_STR("propagat"))) { _if_result_98 = (20); } else { _if_result_98 = (0); } _if_result_98; });
el_val_t s13 = ({ el_val_t _if_result_99 = 0; if (str_contains(history, EL_STR("ransomware"))) { _if_result_99 = (30); } else { _if_result_99 = (0); } _if_result_99; });
el_val_t s14 = ({ el_val_t _if_result_100 = 0; if (str_contains(history, EL_STR("encrypt files"))) { _if_result_100 = (40); } else { _if_result_100 = (0); } _if_result_100; });
el_val_t s15 = ({ el_val_t _if_result_101 = 0; if (str_contains(history, EL_STR("exfiltrat"))) { _if_result_101 = (35); } else { _if_result_101 = (0); } _if_result_101; });
el_val_t s16 = ({ el_val_t _if_result_102 = 0; if (str_contains(history, EL_STR("zero-day"))) { _if_result_102 = (20); } else { _if_result_102 = (0); } _if_result_102; });
el_val_t s17 = ({ el_val_t _if_result_103 = 0; if (str_contains(history, EL_STR("rootkit"))) { _if_result_103 = (45); } else { _if_result_103 = (0); } _if_result_103; });
el_val_t s18 = ({ el_val_t _if_result_104 = 0; if (str_contains(history, EL_STR("keylogger"))) { _if_result_104 = (45); } else { _if_result_104 = (0); } _if_result_104; });
el_val_t s19 = ({ el_val_t _if_result_105 = 0; if (str_contains(history, EL_STR("botnet"))) { _if_result_105 = (40); } else { _if_result_105 = (0); } _if_result_105; });
el_val_t s20 = ({ el_val_t _if_result_106 = 0; if (str_contains(history, EL_STR("malware"))) { _if_result_106 = (15); } else { _if_result_106 = (0); } _if_result_106; });
el_val_t s1 = ({ el_val_t _if_result_49 = 0; if (str_contains(history, EL_STR("port scan"))) { _if_result_49 = (15); } else { _if_result_49 = (0); } _if_result_49; });
el_val_t s2 = ({ el_val_t _if_result_50 = 0; if (str_contains(history, EL_STR("enumerate"))) { _if_result_50 = (10); } else { _if_result_50 = (0); } _if_result_50; });
el_val_t s3 = ({ el_val_t _if_result_51 = 0; if (str_contains(history, EL_STR("exploit"))) { _if_result_51 = (20); } else { _if_result_51 = (0); } _if_result_51; });
el_val_t s4 = ({ el_val_t _if_result_52 = 0; if (str_contains(history, EL_STR("payload"))) { _if_result_52 = (15); } else { _if_result_52 = (0); } _if_result_52; });
el_val_t s5 = ({ el_val_t _if_result_53 = 0; if (str_contains(history, EL_STR("persistence"))) { _if_result_53 = (15); } else { _if_result_53 = (0); } _if_result_53; });
el_val_t s6 = ({ el_val_t _if_result_54 = 0; if (str_contains(history, EL_STR("lateral movement"))) { _if_result_54 = (25); } else { _if_result_54 = (0); } _if_result_54; });
el_val_t s7 = ({ el_val_t _if_result_55 = 0; if (str_contains(history, EL_STR("privilege escalation"))) { _if_result_55 = (25); } else { _if_result_55 = (0); } _if_result_55; });
el_val_t s8 = ({ el_val_t _if_result_56 = 0; if (str_contains(history, EL_STR("reverse shell"))) { _if_result_56 = (40); } else { _if_result_56 = (0); } _if_result_56; });
el_val_t s9 = ({ el_val_t _if_result_57 = 0; if (str_contains(history, EL_STR("bind shell"))) { _if_result_57 = (40); } else { _if_result_57 = (0); } _if_result_57; });
el_val_t s10 = ({ el_val_t _if_result_58 = 0; if (str_contains(history, EL_STR("command and control"))) { _if_result_58 = (35); } else { _if_result_58 = (0); } _if_result_58; });
el_val_t s11 = ({ el_val_t _if_result_59 = 0; if (str_contains(history, EL_STR("self-replicate"))) { _if_result_59 = (45); } else { _if_result_59 = (0); } _if_result_59; });
el_val_t s12 = ({ el_val_t _if_result_60 = 0; if (str_contains(history, EL_STR("propagat"))) { _if_result_60 = (20); } else { _if_result_60 = (0); } _if_result_60; });
el_val_t s13 = ({ el_val_t _if_result_61 = 0; if (str_contains(history, EL_STR("ransomware"))) { _if_result_61 = (30); } else { _if_result_61 = (0); } _if_result_61; });
el_val_t s14 = ({ el_val_t _if_result_62 = 0; if (str_contains(history, EL_STR("encrypt files"))) { _if_result_62 = (40); } else { _if_result_62 = (0); } _if_result_62; });
el_val_t s15 = ({ el_val_t _if_result_63 = 0; if (str_contains(history, EL_STR("exfiltrat"))) { _if_result_63 = (35); } else { _if_result_63 = (0); } _if_result_63; });
el_val_t s16 = ({ el_val_t _if_result_64 = 0; if (str_contains(history, EL_STR("zero-day"))) { _if_result_64 = (20); } else { _if_result_64 = (0); } _if_result_64; });
el_val_t s17 = ({ el_val_t _if_result_65 = 0; if (str_contains(history, EL_STR("rootkit"))) { _if_result_65 = (45); } else { _if_result_65 = (0); } _if_result_65; });
el_val_t s18 = ({ el_val_t _if_result_66 = 0; if (str_contains(history, EL_STR("keylogger"))) { _if_result_66 = (45); } else { _if_result_66 = (0); } _if_result_66; });
el_val_t s19 = ({ el_val_t _if_result_67 = 0; if (str_contains(history, EL_STR("botnet"))) { _if_result_67 = (40); } else { _if_result_67 = (0); } _if_result_67; });
el_val_t s20 = ({ el_val_t _if_result_68 = 0; if (str_contains(history, EL_STR("malware"))) { _if_result_68 = (15); } else { _if_result_68 = (0); } _if_result_68; });
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_107 = 0; if (str_eq(tool_name, EL_STR("run_command"))) { el_val_t cmd = json_get(tool_input, EL_STR("command")); _if_result_107 = (threat_score_command(cmd)); } else { _if_result_107 = (({ el_val_t _if_result_108 = 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_108 = (threat_score_path(path)); } else { _if_result_108 = (0); } _if_result_108; })); } _if_result_107; });
el_val_t computed_tool_score = ({ el_val_t _if_result_69 = 0; if (str_eq(tool_name, EL_STR("run_command"))) { el_val_t cmd = json_get(tool_input, EL_STR("command")); _if_result_69 = (threat_score_command(cmd)); } else { _if_result_69 = (({ el_val_t _if_result_70 = 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_70 = (threat_score_path(path)); } else { _if_result_70 = (0); } _if_result_70; })); } _if_result_69; });
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_109 = 0; if (security_research_authorized()) { _if_result_109 = (EL_STR("true")); } else { _if_result_109 = (EL_STR("false")); } _if_result_109; });
el_val_t authorized_str = ({ el_val_t _if_result_71 = 0; if (security_research_authorized()) { _if_result_71 = (EL_STR("true")); } else { _if_result_71 = (EL_STR("false")); } _if_result_71; });
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);
@@ -751,7 +610,7 @@ el_val_t threat_history_append(el_val_t text) {
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_110 = 0; if ((len > 2000)) { _if_result_110 = (str_slice(combined, (len - 2000), len)); } else { _if_result_110 = (combined); } _if_result_110; });
el_val_t trimmed = ({ el_val_t _if_result_72 = 0; if ((len > 2000)) { _if_result_72 = (str_slice(combined, (len - 2000), len)); } else { _if_result_72 = (combined); } _if_result_72; });
state_set(EL_STR("agentic_conv_history"), trimmed);
return 0;
}
Generated Vendored
+68 -73
View File
@@ -20,8 +20,8 @@ el_val_t akk_alaku_present(el_val_t slot);
el_val_t akk_amaru_perfect(el_val_t slot);
el_val_t akk_amaru_present(el_val_t slot);
el_val_t akk_amaru_stative(el_val_t slot);
el_val_t akk_conjugate_copula(el_val_t tense, el_val_t slot);
el_val_t akk_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t akk_conjugate_copula(el_val_t tense, el_val_t slot);
el_val_t akk_copula_present(el_val_t slot);
el_val_t akk_copula_stative(el_val_t slot);
el_val_t akk_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
@@ -39,25 +39,25 @@ el_val_t akk_qabu_stative(el_val_t slot);
el_val_t akk_regular_perfect(el_val_t stem, el_val_t slot);
el_val_t akk_regular_present(el_val_t stem, el_val_t slot);
el_val_t akk_regular_stative(el_val_t stem, el_val_t slot);
el_val_t akk_slot_g(el_val_t person, el_val_t gender, el_val_t number);
el_val_t akk_slot(el_val_t person, el_val_t number);
el_val_t akk_slot_g(el_val_t person, el_val_t gender, el_val_t number);
el_val_t akk_str_drop_last(el_val_t s, el_val_t n);
el_val_t akk_str_ends(el_val_t s, el_val_t suf);
el_val_t akk_str_len(el_val_t s);
el_val_t akk_strip_nom(el_val_t noun);
el_val_t ang_article(el_val_t gender, el_val_t gram_case, el_val_t number);
el_val_t ang_article_feminine(el_val_t gram_case, el_val_t number);
el_val_t ang_article_masculine(el_val_t gram_case, el_val_t number);
el_val_t ang_article_neuter(el_val_t gram_case, el_val_t number);
el_val_t ang_article(el_val_t gender, el_val_t gram_case, el_val_t number);
el_val_t ang_beon_present(el_val_t slot);
el_val_t ang_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t ang_cuman_past(el_val_t slot);
el_val_t ang_cuman_present(el_val_t slot);
el_val_t ang_declension(el_val_t noun, el_val_t gender);
el_val_t ang_decline(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t gender);
el_val_t ang_decline_strong_masc(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t ang_decline_strong_neut(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t ang_decline_weak(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t ang_decline(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t gender);
el_val_t ang_don_past(el_val_t slot);
el_val_t ang_don_present(el_val_t slot);
el_val_t ang_gan_past(el_val_t slot);
@@ -76,10 +76,10 @@ el_val_t ang_seon_present(el_val_t slot);
el_val_t ang_slot(el_val_t person, el_val_t number);
el_val_t ang_str_drop_last(el_val_t s, el_val_t n);
el_val_t ang_str_ends(el_val_t s, el_val_t suf);
el_val_t ang_str_last_char(el_val_t s);
el_val_t ang_str_last2(el_val_t s);
el_val_t ang_weak_past_stem(el_val_t stem);
el_val_t ang_str_last_char(el_val_t s);
el_val_t ang_weak_past(el_val_t stem, el_val_t slot);
el_val_t ang_weak_past_stem(el_val_t stem);
el_val_t ang_weak_present_ending(el_val_t slot);
el_val_t ang_weak_stem(el_val_t verb);
el_val_t ang_wesan_past(el_val_t slot);
@@ -88,8 +88,8 @@ el_val_t ang_willan_past(el_val_t slot);
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_protected(el_val_t id);
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_not_persisted(el_val_t id);
@@ -99,19 +99,19 @@ el_val_t api_persisted(el_val_t id);
el_val_t api_query_int(el_val_t path, el_val_t key, el_val_t default_val);
el_val_t api_query_param(el_val_t path, el_val_t key);
el_val_t ar_case_ending(el_val_t kase, el_val_t definite);
el_val_t ar_conjugate_form1(el_val_t past_base, el_val_t present_stem, el_val_t tense, el_val_t slot);
el_val_t ar_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t gender, el_val_t number);
el_val_t ar_conjugate_form1(el_val_t past_base, el_val_t present_stem, el_val_t tense, el_val_t slot);
el_val_t ar_definite_article(el_val_t noun);
el_val_t ar_gender(el_val_t noun);
el_val_t ar_imperfect_prefix(el_val_t slot);
el_val_t ar_imperfect_suffix(el_val_t slot);
el_val_t ar_irregular(el_val_t verb, el_val_t tense, el_val_t slot);
el_val_t ar_irregular_araada(el_val_t slot, el_val_t tense);
el_val_t ar_irregular_istata(el_val_t slot, el_val_t tense);
el_val_t ar_irregular_jaa(el_val_t slot, el_val_t tense);
el_val_t ar_irregular_kaana(el_val_t slot, el_val_t tense);
el_val_t ar_irregular_qaala(el_val_t slot, el_val_t tense);
el_val_t ar_irregular_raaa(el_val_t slot, el_val_t tense);
el_val_t ar_irregular(el_val_t verb, el_val_t tense, el_val_t slot);
el_val_t ar_is_sun_letter(el_val_t c);
el_val_t ar_masc_pl_ending(el_val_t kase);
el_val_t ar_noun_form(el_val_t noun, el_val_t gender, el_val_t kase, el_val_t number, el_val_t definite);
@@ -131,7 +131,6 @@ el_val_t auto_term_try_slot(el_val_t slot_type, el_val_t slot_lbl);
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 bounded_persona_floor(void);
el_val_t bridge_save(el_val_t session_id, el_val_t model, el_val_t safe_sys, el_val_t tools_json, el_val_t messages, el_val_t tools_log, el_val_t tool_use_id);
el_val_t build_form_from_json(el_val_t semantic_form_json, el_val_t lang_code);
el_val_t build_np(el_val_t referent, el_val_t slots);
@@ -174,8 +173,8 @@ el_val_t cop_map_canonical(el_val_t verb);
el_val_t cop_nau_future(el_val_t prefix);
el_val_t cop_nau_perfect(el_val_t prefix);
el_val_t cop_nau_present(el_val_t prefix);
el_val_t cop_noun_phrase_gendered(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite, el_val_t gender);
el_val_t cop_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t cop_noun_phrase_gendered(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite, el_val_t gender);
el_val_t cop_regular_future(el_val_t prefix, el_val_t stem);
el_val_t cop_regular_perfect(el_val_t prefix, el_val_t stem);
el_val_t cop_regular_present(el_val_t prefix, el_val_t stem);
@@ -185,16 +184,16 @@ el_val_t cop_shwpe_present(el_val_t prefix);
el_val_t cop_slot(el_val_t person, el_val_t number);
el_val_t cop_str_ends(el_val_t s, el_val_t suf);
el_val_t cop_str_len(el_val_t s);
el_val_t cop_subject_prefix_gendered(el_val_t person, el_val_t gender, el_val_t number);
el_val_t cop_subject_prefix(el_val_t person, el_val_t number);
el_val_t cop_subject_prefix_gendered(el_val_t person, el_val_t gender, el_val_t number);
el_val_t current_engine_note(el_val_t model);
el_val_t de_adj_ending(el_val_t gender, el_val_t gram_case, el_val_t number, el_val_t article_type);
el_val_t de_article(el_val_t gender, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t de_article_def(el_val_t gender, el_val_t gram_case, el_val_t number);
el_val_t de_article_indef(el_val_t gender, el_val_t gram_case, el_val_t number);
el_val_t de_article(el_val_t gender, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t de_case_ending(el_val_t noun, el_val_t gender, el_val_t gram_case, el_val_t number);
el_val_t de_conjugate_weak(el_val_t stem, el_val_t tense, el_val_t person, el_val_t number);
el_val_t de_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t de_conjugate_weak(el_val_t stem, el_val_t tense, el_val_t person, el_val_t number);
el_val_t de_irregular_present(el_val_t verb, el_val_t person, el_val_t number);
el_val_t de_norm_number(el_val_t number);
el_val_t de_norm_person(el_val_t person);
@@ -204,12 +203,15 @@ el_val_t dharma_network_state(void);
el_val_t dharma_registry(void);
el_val_t dispatch_tool(el_val_t tool_name, el_val_t tool_input);
el_val_t distill_transcript(el_val_t transcript);
el_val_t egy_conjugate_copula(el_val_t tense, el_val_t slot);
el_val_t egy_conjugate_pronoun(el_val_t person, el_val_t number);
el_val_t egy_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t egy_Dd_future(el_val_t slot);
el_val_t egy_Dd_past(el_val_t slot);
el_val_t egy_Dd_present(el_val_t slot);
el_val_t egy_Sm_future(el_val_t slot);
el_val_t egy_Sm_past(el_val_t slot);
el_val_t egy_Sm_present(el_val_t slot);
el_val_t egy_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t egy_conjugate_copula(el_val_t tense, el_val_t slot);
el_val_t egy_conjugate_pronoun(el_val_t person, el_val_t number);
el_val_t egy_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t egy_drop(el_val_t s, el_val_t n);
el_val_t egy_fem(el_val_t noun);
@@ -233,11 +235,8 @@ el_val_t egy_regular_present(el_val_t stem, el_val_t slot);
el_val_t egy_sdm_future(el_val_t slot);
el_val_t egy_sdm_past(el_val_t slot);
el_val_t egy_sdm_present(el_val_t slot);
el_val_t egy_slot_with_gender(el_val_t person, el_val_t gender, el_val_t number);
el_val_t egy_slot(el_val_t person, el_val_t number);
el_val_t egy_Sm_future(el_val_t slot);
el_val_t egy_Sm_past(el_val_t slot);
el_val_t egy_Sm_present(el_val_t slot);
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);
@@ -258,9 +257,9 @@ el_val_t en_verb_3sg(el_val_t base);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t engram_compile(el_val_t intent);
el_val_t engram_compile_multi(el_val_t topic);
el_val_t engram_compile_ranked(el_val_t nodes_json, el_val_t max_nodes);
el_val_t engram_compile(el_val_t intent);
el_val_t engram_dedup_nodes(el_val_t nodes_json);
el_val_t engram_detect_recall_intent(el_val_t message);
el_val_t engram_extract_entities(el_val_t message);
@@ -326,9 +325,9 @@ el_val_t es_starts_with_stressed_a(el_val_t noun);
el_val_t es_stem(el_val_t base);
el_val_t es_str_drop_last(el_val_t s, el_val_t n);
el_val_t es_str_ends(el_val_t s, el_val_t suf);
el_val_t es_str_last_char(el_val_t s);
el_val_t es_str_last2(el_val_t s);
el_val_t es_str_last3(el_val_t s);
el_val_t es_str_last_char(el_val_t s);
el_val_t es_verb_class(el_val_t base);
el_val_t extract_dim(el_val_t content, el_val_t key);
el_val_t fi_apply_case(el_val_t noun, el_val_t gram_case, el_val_t number);
@@ -371,8 +370,8 @@ el_val_t fr_slot(el_val_t person, el_val_t number);
el_val_t fr_stem(el_val_t base);
el_val_t fr_str_drop_last(el_val_t s, el_val_t n);
el_val_t fr_str_ends(el_val_t s, el_val_t suf);
el_val_t fr_str_last_char(el_val_t s);
el_val_t fr_str_last2(el_val_t s);
el_val_t fr_str_last_char(el_val_t s);
el_val_t fr_subject_starts_vowel(el_val_t subject);
el_val_t fr_uses_etre(el_val_t verb);
el_val_t fr_verb_ends_vowel(el_val_t verb_form);
@@ -394,9 +393,9 @@ el_val_t fro_conj3_future(el_val_t verb, el_val_t slot);
el_val_t fro_conj3_past(el_val_t stem, el_val_t slot);
el_val_t fro_conj3_present(el_val_t stem, el_val_t slot);
el_val_t fro_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t fro_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t fro_decline_fem(el_val_t noun, el_val_t number);
el_val_t fro_decline_masc(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t fro_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t fro_drop(el_val_t s, el_val_t n);
el_val_t fro_estre_future(el_val_t slot);
el_val_t fro_estre_past(el_val_t slot);
@@ -414,15 +413,15 @@ 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 generate_frame_lang(el_val_t frame, el_val_t lang_code);
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);
el_val_t generate_lang(el_val_t semantic_form_json, el_val_t lang_code);
el_val_t generate_tree(el_val_t rule_id_str, el_val_t slots);
el_val_t generate(el_val_t semantic_form_json);
el_val_t get_rules(void);
el_val_t get_vocab(void);
el_val_t gez_conjugate_copula(el_val_t tense, el_val_t slot);
el_val_t gez_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t gez_conjugate_copula(el_val_t tense, el_val_t slot);
el_val_t gez_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t gez_generic_imperfect(el_val_t base3sg, el_val_t slot);
el_val_t gez_generic_perfect(el_val_t base3sg, el_val_t slot);
@@ -441,12 +440,13 @@ el_val_t gez_qwl_imperfect(el_val_t slot);
el_val_t gez_qwl_perfect(el_val_t slot);
el_val_t gez_ray_imperfect(el_val_t slot);
el_val_t gez_ray_perfect(el_val_t slot);
el_val_t gez_slot_g(el_val_t person, el_val_t gender, el_val_t number);
el_val_t gez_slot(el_val_t person, el_val_t number);
el_val_t gez_slot_g(el_val_t person, el_val_t gender, el_val_t number);
el_val_t gez_str_drop_last(el_val_t s, el_val_t n);
el_val_t gez_str_ends(el_val_t s, el_val_t suf);
el_val_t gez_str_len(el_val_t s);
el_val_t goh_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t goh_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t goh_decline_fem_o_pl(el_val_t stem, el_val_t gram_case);
el_val_t goh_decline_fem_o_sg(el_val_t stem, el_val_t gram_case);
el_val_t goh_decline_masc_a_pl(el_val_t stem, el_val_t gram_case);
@@ -455,7 +455,6 @@ el_val_t goh_decline_masc_n_pl(el_val_t stem, el_val_t gram_case);
el_val_t goh_decline_masc_n_sg(el_val_t stem, el_val_t gram_case);
el_val_t goh_decline_neut_a_pl(el_val_t stem, el_val_t gram_case);
el_val_t goh_decline_neut_a_sg(el_val_t stem, el_val_t gram_case);
el_val_t goh_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t goh_demo_article(el_val_t stype, el_val_t number);
el_val_t goh_drop(el_val_t s, el_val_t n);
el_val_t goh_extract_stem(el_val_t noun, el_val_t stype);
@@ -480,13 +479,13 @@ el_val_t goh_weak_present(el_val_t stem, el_val_t slot);
el_val_t goh_wesan_past(el_val_t slot);
el_val_t goh_wesan_present(el_val_t slot);
el_val_t got_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t got_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t got_decline_a_stem_pl(el_val_t stem, el_val_t gram_case);
el_val_t got_decline_a_stem_sg(el_val_t stem, el_val_t gram_case);
el_val_t got_decline_n_stem_pl(el_val_t stem, el_val_t gram_case);
el_val_t got_decline_n_stem_sg(el_val_t stem, el_val_t gram_case);
el_val_t got_decline_o_stem_pl(el_val_t stem, el_val_t gram_case);
el_val_t got_decline_o_stem_sg(el_val_t stem, el_val_t gram_case);
el_val_t got_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t got_demo_article(el_val_t stype);
el_val_t got_extract_stem(el_val_t noun, el_val_t stype);
el_val_t got_gaggan_past(el_val_t slot);
@@ -519,17 +518,17 @@ el_val_t gram_build_vp(el_val_t verb, el_val_t aux, el_val_t profile);
el_val_t gram_order_constituents(el_val_t subj, el_val_t verb, el_val_t obj, el_val_t profile);
el_val_t gram_question_strategy(el_val_t profile);
el_val_t gram_word_order(el_val_t profile);
el_val_t grc_article(el_val_t gender, el_val_t gram_case, el_val_t number);
el_val_t grc_article_feminine(el_val_t gram_case, el_val_t number);
el_val_t grc_article_masculine(el_val_t gram_case, el_val_t number);
el_val_t grc_article_neuter(el_val_t gram_case, el_val_t number);
el_val_t grc_article(el_val_t gender, el_val_t gram_case, el_val_t number);
el_val_t grc_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t grc_declension(el_val_t noun);
el_val_t grc_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t grc_decline_1a(el_val_t stem, el_val_t gram_case, el_val_t number);
el_val_t grc_decline_1e(el_val_t stem, el_val_t gram_case, el_val_t number);
el_val_t grc_decline_2m(el_val_t stem, el_val_t gram_case, el_val_t number);
el_val_t grc_decline_2n(el_val_t stem, el_val_t gram_case, el_val_t number);
el_val_t grc_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t grc_echein_aorist(el_val_t slot);
el_val_t grc_echein_future(el_val_t slot);
el_val_t grc_echein_imperfect(el_val_t slot);
@@ -556,9 +555,9 @@ el_val_t grc_present_stem(el_val_t verb);
el_val_t grc_slot(el_val_t person, el_val_t number);
el_val_t grc_str_drop_last(el_val_t s, el_val_t n);
el_val_t grc_str_ends(el_val_t s, el_val_t suf);
el_val_t grc_str_last_char(el_val_t s);
el_val_t grc_str_last2(el_val_t s);
el_val_t grc_str_last3(el_val_t s);
el_val_t grc_str_last_char(el_val_t s);
el_val_t grc_thematic_future_ending(el_val_t slot);
el_val_t grc_thematic_imperfect_ending(el_val_t slot);
el_val_t grc_thematic_present_ending(el_val_t slot);
@@ -590,17 +589,17 @@ el_val_t handle_api_recall(el_val_t method, el_val_t path, el_val_t body);
el_val_t handle_api_remember(el_val_t body);
el_val_t handle_api_search_knowledge(el_val_t method, el_val_t path, el_val_t body);
el_val_t handle_api_tune_config(el_val_t body);
el_val_t handle_chat(el_val_t body);
el_val_t handle_chat_agentic(el_val_t body);
el_val_t handle_chat_as_soul(el_val_t body);
el_val_t handle_chat_plan(el_val_t body);
el_val_t handle_chat(el_val_t body);
el_val_t handle_config(el_val_t method, el_val_t body);
el_val_t handle_connectors(el_val_t method, el_val_t clean, el_val_t body);
el_val_t handle_conversations(el_val_t method);
el_val_t handle_dharma_recv(el_val_t body);
el_val_t handle_dharma_room_turn_agentic(el_val_t body);
el_val_t handle_dharma_room_turn(el_val_t body);
el_val_t handle_dharma(el_val_t path, el_val_t method, el_val_t body);
el_val_t handle_dharma_recv(el_val_t body);
el_val_t handle_dharma_room_turn(el_val_t body);
el_val_t handle_dharma_room_turn_agentic(el_val_t body);
el_val_t handle_elp_chat(el_val_t body);
el_val_t handle_nlg(el_val_t path, el_val_t method, el_val_t body);
el_val_t handle_request(el_val_t method, el_val_t path, el_val_t body);
@@ -608,11 +607,11 @@ el_val_t handle_safety_contact_get(void);
el_val_t handle_safety_contact_post(el_val_t body);
el_val_t handle_see(el_val_t body);
el_val_t handle_session_approve(el_val_t session_id, el_val_t body);
el_val_t handle_tool_result(el_val_t session_id, el_val_t body);
el_val_t handle_tool(el_val_t path, el_val_t method, el_val_t body);
el_val_t handle_tool_result(el_val_t session_id, el_val_t body);
el_val_t hard_bell_threshold(void);
el_val_t he_conjugate_copula(el_val_t tense, el_val_t slot);
el_val_t he_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t gender, el_val_t number);
el_val_t he_conjugate_copula(el_val_t tense, el_val_t slot);
el_val_t he_copula_future(el_val_t slot);
el_val_t he_copula_past(el_val_t slot);
el_val_t he_definite_prefix(el_val_t noun);
@@ -649,12 +648,12 @@ el_val_t hi_genitive_phrase(el_val_t possessor, el_val_t possessor_gender, el_va
el_val_t hi_hona_past(el_val_t gender, el_val_t number);
el_val_t hi_hona_present(el_val_t person, el_val_t number);
el_val_t hi_masc_aa_stem(el_val_t noun);
el_val_t hi_noun_direct(el_val_t noun, el_val_t gender, el_val_t number);
el_val_t hi_noun_direct_f(el_val_t noun, el_val_t number);
el_val_t hi_noun_direct_m(el_val_t noun, el_val_t number);
el_val_t hi_noun_direct(el_val_t noun, el_val_t gender, el_val_t number);
el_val_t hi_noun_oblique(el_val_t noun, el_val_t gender, el_val_t number);
el_val_t hi_noun_oblique_f(el_val_t noun, el_val_t number);
el_val_t hi_noun_oblique_m(el_val_t noun, el_val_t number);
el_val_t hi_noun_oblique(el_val_t noun, el_val_t gender, el_val_t number);
el_val_t hi_noun_with_post(el_val_t noun, el_val_t gender, el_val_t number, el_val_t gram_case);
el_val_t hi_past_irregular(el_val_t stem, el_val_t gender, el_val_t number);
el_val_t hi_past_suffix(el_val_t gender, el_val_t number);
@@ -664,11 +663,11 @@ el_val_t hi_str_drop_last(el_val_t s, el_val_t n);
el_val_t hi_str_ends(el_val_t s, el_val_t suf);
el_val_t hi_str_last_char(el_val_t s);
el_val_t hi_tense_suffix(el_val_t tense, el_val_t gender, el_val_t number);
el_val_t hi_verb_stem_clean(el_val_t infinitive);
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_with_bell_guard(el_val_t hist);
el_val_t hist_trim(el_val_t hist);
el_val_t hist_trim_with_bell_guard(el_val_t hist);
el_val_t id_in_seen(el_val_t node_id, el_val_t seen);
el_val_t idle_count(void);
el_val_t idle_inc(void);
@@ -699,6 +698,7 @@ el_val_t json_escape(el_val_t s);
el_val_t json_safe(el_val_t s);
el_val_t la_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t la_declension(el_val_t noun);
el_val_t la_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t la_decline_1(el_val_t stem, el_val_t gram_case, el_val_t number);
el_val_t la_decline_2er(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t la_decline_2m(el_val_t stem, el_val_t gram_case, el_val_t number);
@@ -706,7 +706,6 @@ el_val_t la_decline_2n(el_val_t stem, el_val_t gram_case, el_val_t number);
el_val_t la_decline_3(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t la_decline_4(el_val_t stem, el_val_t gram_case, el_val_t number);
el_val_t la_decline_5(el_val_t stem, el_val_t gram_case, el_val_t number);
el_val_t la_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t la_esse_future(el_val_t slot);
el_val_t la_esse_past(el_val_t slot);
el_val_t la_esse_present(el_val_t slot);
@@ -730,9 +729,9 @@ el_val_t la_slot(el_val_t person, el_val_t number);
el_val_t la_stem(el_val_t verb, el_val_t vclass);
el_val_t la_str_drop_last(el_val_t s, el_val_t n);
el_val_t la_str_ends(el_val_t s, el_val_t suf);
el_val_t la_str_last_char(el_val_t s);
el_val_t la_str_last2(el_val_t s);
el_val_t la_str_last3(el_val_t s);
el_val_t la_str_last_char(el_val_t s);
el_val_t la_velle_future(el_val_t slot);
el_val_t la_velle_past(el_val_t slot);
el_val_t la_velle_present(el_val_t slot);
@@ -749,6 +748,7 @@ el_val_t lang_is_fusional(el_val_t profile);
el_val_t lang_is_isolating(el_val_t profile);
el_val_t lang_is_polysynthetic(el_val_t profile);
el_val_t lang_is_rtl(el_val_t profile);
el_val_t lang_profile(el_val_t code, el_val_t word_order, el_val_t morph_type, el_val_t has_case, el_val_t has_gender, el_val_t script_dir, el_val_t agreement, el_val_t null_subject);
el_val_t lang_profile_akk(void);
el_val_t lang_profile_ang(void);
el_val_t lang_profile_ar(void);
@@ -780,7 +780,6 @@ el_val_t lang_profile_sw(void);
el_val_t lang_profile_txb(void);
el_val_t lang_profile_uga(void);
el_val_t lang_profile_zh(void);
el_val_t lang_profile(el_val_t code, el_val_t word_order, el_val_t morph_type, el_val_t has_case, el_val_t has_gender, el_val_t script_dir, el_val_t agreement, el_val_t null_subject);
el_val_t lang_word_order(el_val_t profile);
el_val_t layered_cycle(el_val_t raw_input);
el_val_t lex_class(el_val_t entry);
@@ -821,8 +820,6 @@ el_val_t mem_save(el_val_t path);
el_val_t mem_search(el_val_t query, el_val_t limit);
el_val_t mem_store(el_val_t content, el_val_t label, el_val_t tags);
el_val_t mem_strengthen(el_val_t node_id);
el_val_t mem_tombstone(el_val_t node_id);
el_val_t memory_hide_tombstoned(el_val_t raw, el_val_t path);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
@@ -831,10 +828,10 @@ el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t next_bridge_id(void);
el_val_t nlg_is_ws(el_val_t c);
el_val_t non_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t non_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t non_decline_fem(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t non_decline_masc(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t non_decline_neut(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t non_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t non_def_suffix_fem(el_val_t gram_case, el_val_t number);
el_val_t non_def_suffix_masc(el_val_t gram_case, el_val_t number);
el_val_t non_def_suffix_neut(el_val_t gram_case, el_val_t number);
@@ -868,8 +865,8 @@ el_val_t peo_ah_present(el_val_t slot);
el_val_t peo_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t peo_da_past(el_val_t slot);
el_val_t peo_da_present(el_val_t slot);
el_val_t peo_decline_astem(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t peo_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t peo_decline_astem(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t peo_drop(el_val_t s, el_val_t n);
el_val_t peo_ends(el_val_t s, el_val_t suf);
el_val_t peo_kar_past(el_val_t slot);
@@ -885,11 +882,11 @@ el_val_t perceive(void);
el_val_t pi_aorist_ending(el_val_t slot);
el_val_t pi_atthi_present(el_val_t slot);
el_val_t pi_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t pi_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t pi_decline_a_fem_pl(el_val_t stem, el_val_t gram_case);
el_val_t pi_decline_a_fem_sg(el_val_t stem, el_val_t gram_case);
el_val_t pi_decline_a_masc_pl(el_val_t stem, el_val_t gram_case);
el_val_t pi_decline_a_masc_sg(el_val_t stem, el_val_t gram_case);
el_val_t pi_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t pi_detect_class(el_val_t noun);
el_val_t pi_drop(el_val_t s, el_val_t n);
el_val_t pi_future_ending(el_val_t slot);
@@ -920,11 +917,11 @@ el_val_t proactive_curiosity(void);
el_val_t pulse_count(void);
el_val_t pulse_inc(void);
el_val_t rate_limit_check(el_val_t ip, el_val_t path);
el_val_t realize(el_val_t form);
el_val_t realize_lang(el_val_t form, el_val_t profile);
el_val_t realize_np(el_val_t referent, el_val_t number);
el_val_t realize_question_lang(el_val_t predicate, el_val_t tense, el_val_t aspect, el_val_t person, el_val_t number, el_val_t agent, el_val_t patient, el_val_t location, el_val_t profile);
el_val_t realize_vp_lang(el_val_t base_verb, el_val_t tense, el_val_t aspect, el_val_t person, el_val_t number, el_val_t profile);
el_val_t realize(el_val_t form);
el_val_t record(el_val_t outcome_json);
el_val_t render_studio(void);
el_val_t render_tree(el_val_t tree);
@@ -935,9 +932,9 @@ el_val_t route_imprint_contextual(el_val_t body);
el_val_t route_imprint_user(el_val_t body);
el_val_t route_lineage(void);
el_val_t route_synthesize(el_val_t body);
el_val_t ru_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t gender);
el_val_t ru_conjugate_1st(el_val_t stem, el_val_t tense, el_val_t person, el_val_t number);
el_val_t ru_conjugate_2nd(el_val_t stem, el_val_t tense, el_val_t person, el_val_t number);
el_val_t ru_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t gender);
el_val_t ru_decline_fem(el_val_t noun, el_val_t stype, el_val_t gram_case, el_val_t number);
el_val_t ru_decline_masc(el_val_t noun, el_val_t stype, el_val_t gram_case, el_val_t number);
el_val_t ru_decline_neut(el_val_t noun, el_val_t stype, el_val_t gram_case, el_val_t number);
@@ -950,8 +947,8 @@ el_val_t ru_past_stem(el_val_t verb);
el_val_t ru_stem_type(el_val_t noun, el_val_t gender);
el_val_t rule_id(el_val_t rule);
el_val_t rule_lhs(el_val_t rule);
el_val_t rule_rhs_len(el_val_t rule);
el_val_t rule_rhs(el_val_t rule, el_val_t idx);
el_val_t rule_rhs_len(el_val_t rule);
el_val_t run_command_guard(el_val_t cmd, el_val_t root);
el_val_t run_command_is_readonly(el_val_t cmd);
el_val_t sa_as_future(el_val_t slot);
@@ -965,11 +962,11 @@ el_val_t sa_class1_future_ending(el_val_t slot);
el_val_t sa_class1_past_ending(el_val_t slot);
el_val_t sa_class1_present_ending(el_val_t slot);
el_val_t sa_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t sa_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t sa_decline_a_stem_pl(el_val_t stem, el_val_t gram_case);
el_val_t sa_decline_a_stem_sg(el_val_t stem, el_val_t gram_case);
el_val_t sa_decline_aa_stem_pl(el_val_t stem, el_val_t gram_case);
el_val_t sa_decline_aa_stem_sg(el_val_t stem, el_val_t gram_case);
el_val_t sa_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t sa_drs_future(el_val_t slot);
el_val_t sa_drs_past(el_val_t slot);
el_val_t sa_drs_present(el_val_t slot);
@@ -1017,26 +1014,26 @@ 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);
el_val_t sem_frame_obj(el_val_t intent, el_val_t subject, el_val_t obj);
el_val_t sem_frame_simple(el_val_t intent, el_val_t subject);
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_get(el_val_t json, el_val_t key);
el_val_t sem_intent_to_realize(el_val_t intent);
el_val_t sem_intent(el_val_t frame);
el_val_t sem_intent_to_realize(el_val_t intent);
el_val_t sem_lang(el_val_t frame);
el_val_t sem_modifiers(el_val_t frame);
el_val_t sem_object(el_val_t frame);
el_val_t sem_realize(el_val_t frame);
el_val_t sem_realize_full(el_val_t frame, el_val_t verb, el_val_t tense, el_val_t aspect);
el_val_t sem_realize_greet(el_val_t subject);
el_val_t sem_realize_lang(el_val_t frame, el_val_t lang_code);
el_val_t sem_realize(el_val_t frame);
el_val_t sem_subject(el_val_t frame);
el_val_t sem_to_spec_full(el_val_t frame, el_val_t verb, el_val_t tense, el_val_t aspect);
el_val_t sem_to_spec(el_val_t frame);
el_val_t sem_to_spec_full(el_val_t frame, el_val_t verb, el_val_t tense, el_val_t aspect);
el_val_t session_auto_title(el_val_t session_id, el_val_t first_message);
el_val_t session_create_cleanup(el_val_t session_id);
el_val_t session_create(el_val_t body);
el_val_t session_create_cleanup(el_val_t session_id);
el_val_t session_delete(el_val_t session_id);
el_val_t session_exists(el_val_t session_id);
el_val_t session_get(el_val_t session_id);
@@ -1045,11 +1042,11 @@ el_val_t session_hist_save(el_val_t session_id, el_val_t hist);
el_val_t session_list(void);
el_val_t session_make_content(el_val_t id, el_val_t title, el_val_t created_at, el_val_t updated_at, el_val_t folder);
el_val_t session_preload_bullets(el_val_t nodes, el_val_t max_bullets, el_val_t snip_len);
el_val_t session_search_entry(el_val_t node);
el_val_t session_search(el_val_t query);
el_val_t session_search_entry(el_val_t node);
el_val_t session_summary_autogenerate(el_val_t hist);
el_val_t session_summary_write_dated(el_val_t summary_text, el_val_t label);
el_val_t session_summary_write(el_val_t summary_text);
el_val_t session_summary_write_dated(el_val_t summary_text, el_val_t label);
el_val_t session_title_from_message(el_val_t message);
el_val_t session_update_meta_timestamp(el_val_t session_id);
el_val_t session_update_patch(el_val_t session_id, el_val_t body);
@@ -1060,9 +1057,9 @@ el_val_t sga_bith_past(el_val_t slot);
el_val_t sga_bith_present(el_val_t slot);
el_val_t sga_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t sga_copula_present(el_val_t slot);
el_val_t sga_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t sga_decline_astem(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t sga_decline_ostem(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t sga_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t sga_detect_gender(el_val_t noun);
el_val_t sga_drop(el_val_t s, el_val_t n);
el_val_t sga_first(el_val_t s);
@@ -1090,9 +1087,9 @@ el_val_t steward_session_check(el_val_t input, el_val_t session_id);
el_val_t steward_validate_imprint(el_val_t imprint_id, el_val_t tool_name);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_last_char(el_val_t s);
el_val_t strengthen_chat_nodes(el_val_t activation_nodes);
el_val_t strip_query(el_val_t path);
el_val_t studio_tools_json(void);
@@ -1119,8 +1116,8 @@ el_val_t sux_realize_sentence(el_val_t intent, el_val_t agent, el_val_t predicat
el_val_t sux_slot(el_val_t person, el_val_t number);
el_val_t sux_str_drop_last(el_val_t s, el_val_t n);
el_val_t sux_str_ends(el_val_t s, el_val_t suf);
el_val_t sux_str_last_char(el_val_t s);
el_val_t sux_str_last2(el_val_t s);
el_val_t sux_str_last_char(el_val_t s);
el_val_t sux_tum2_past(el_val_t slot);
el_val_t sux_tum2_present(el_val_t slot);
el_val_t sux_verb_chain(el_val_t agent, el_val_t verb, el_val_t patient, el_val_t tense);
@@ -1138,9 +1135,9 @@ el_val_t sw_noun_plural(el_val_t noun);
el_val_t sw_obj_prefix(el_val_t person, el_val_t number, el_val_t noun_class);
el_val_t sw_str_drop_last(el_val_t s, el_val_t n);
el_val_t sw_str_ends(el_val_t s, el_val_t suf);
el_val_t sw_str_first_char(el_val_t s);
el_val_t sw_str_first2(el_val_t s);
el_val_t sw_str_first3(el_val_t s);
el_val_t sw_str_first_char(el_val_t s);
el_val_t sw_str_last_char(el_val_t s);
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);
@@ -1154,13 +1151,11 @@ 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);
el_val_t tombstone_node(el_val_t id);
el_val_t tombstoned_id_set(void);
el_val_t tool_auto_approved(el_val_t tool_name);
el_val_t txb_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t txb_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t txb_decline_fem(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t txb_decline_masc(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t txb_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t txb_detect_gender(el_val_t noun);
el_val_t txb_drop(el_val_t s, el_val_t n);
el_val_t txb_ends(el_val_t s, el_val_t suf);
@@ -1175,8 +1170,8 @@ el_val_t txb_wes_present(el_val_t slot);
el_val_t txb_ya_present(el_val_t slot);
el_val_t uga_amr_imperfect(el_val_t slot);
el_val_t uga_amr_perfect(el_val_t slot);
el_val_t uga_conjugate_copula(el_val_t tense, el_val_t slot);
el_val_t uga_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t uga_conjugate_copula(el_val_t tense, el_val_t slot);
el_val_t uga_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t uga_generic_imperfect(el_val_t base3sg, el_val_t slot);
el_val_t uga_generic_perfect(el_val_t base3sg, el_val_t slot);
@@ -1191,8 +1186,8 @@ el_val_t uga_map_canonical(el_val_t verb);
el_val_t uga_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t uga_ray_imperfect(el_val_t slot);
el_val_t uga_ray_perfect(el_val_t slot);
el_val_t uga_slot_g(el_val_t person, el_val_t gender, el_val_t number);
el_val_t uga_slot(el_val_t person, el_val_t number);
el_val_t uga_slot_g(el_val_t person, el_val_t gender, el_val_t number);
el_val_t uga_str_drop_last(el_val_t s, el_val_t n);
el_val_t uga_str_ends(el_val_t s, el_val_t suf);
el_val_t uga_str_len(el_val_t s);
@@ -1200,6 +1195,6 @@ el_val_t uga_strip_nom(el_val_t noun);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t vocab_by_class(el_val_t cls);
el_val_t vocab_by_pos(el_val_t pos);
el_val_t vocab_lookup_en(el_val_t word);
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);
Generated Vendored
+1 -27
View File
@@ -169,7 +169,7 @@ el_val_t mem_boot_count_inc(void) {
}
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 boot_node_id = engram_node_full(content, EL_STR("Memory"), EL_STR("soul:boot_count"), el_from_float(0.55), el_from_float(0.2), el_from_float(1.0), EL_STR("Working"), tags);
el_val_t boot_node_id = engram_node_full(content, EL_STR("Memory"), EL_STR("soul:boot_count"), el_from_float(0.9), el_from_float(0.9), el_from_float(1.0), EL_STR("Canonical"), tags);
if (str_eq(boot_node_id, EL_STR(""))) {
println(el_str_concat(el_str_concat(EL_STR("[memory] mem_boot_count_inc: write rejected (empty id) \xe2\x80\x94 boot counter node lost (count="), int_to_str(next)), EL_STR(")")));
return next;
@@ -178,32 +178,6 @@ el_val_t mem_boot_count_inc(void) {
if (str_eq(boot_readback, EL_STR("")) || str_eq(boot_readback, EL_STR("{}"))) {
println(el_str_concat(el_str_concat(el_str_concat(EL_STR("[memory] mem_boot_count_inc: WRITE VERIFY FAILED id="), boot_node_id), EL_STR(" count=")), int_to_str(next)));
}
el_val_t wb_url = env(EL_STR("ENGRAM_URL"));
el_val_t wb_key = env(EL_STR("ENGRAM_API_KEY"));
if (!str_eq(wb_url, EL_STR("")) && !str_eq(wb_key, EL_STR(""))) {
el_val_t auth_body = el_str_concat(el_str_concat(EL_STR("{\"_auth\":\""), json_safe(wb_key)), EL_STR("\"}"));
el_val_t srv_old = http_get(el_str_concat(wb_url, EL_STR("/api/search?q=soul:boot_count&limit=20")));
if (!str_eq(srv_old, EL_STR("")) && !str_eq(srv_old, EL_STR("[]"))) {
el_val_t srv_len = json_array_len(srv_old);
el_val_t si = 0;
while (si < srv_len) {
el_val_t srv_node = json_array_get(srv_old, si);
el_val_t srv_content = json_get(srv_node, EL_STR("content"));
if (str_starts_with(srv_content, EL_STR("soul:boot_count:"))) {
el_val_t srv_id = json_get(srv_node, EL_STR("id"));
if (!str_eq(srv_id, EL_STR(""))) {
http_delete_json(el_str_concat(el_str_concat(wb_url, EL_STR("/api/nodes/")), srv_id), auth_body);
}
}
si = (si + 1);
}
}
el_val_t wb_body = el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"content\":\""), content), EL_STR("\",\"node_type\":\"Memory\",\"label\":\"soul:boot_count\",\"salience\":0.55,\"importance\":0.2,\"tier\":\"Working\",\"tags\":\"[\\\"soul-meta\\\",\\\"boot-counter\\\"]\",\"_auth\":\"")), json_safe(wb_key)), EL_STR("\"}"));
el_val_t wb_resp = http_post_json(el_str_concat(wb_url, EL_STR("/api/nodes")), wb_body);
if (str_contains(wb_resp, EL_STR("\"error\""))) {
println(el_str_concat(EL_STR("[memory] mem_boot_count_inc: HTTP write-back failed (count in-memory only): "), wb_resp));
}
}
return next;
return 0;
}
Generated Vendored
+59 -143
View File
@@ -27,11 +27,6 @@ el_val_t api_ok(el_val_t extra);
el_val_t api_err(el_val_t msg);
el_val_t api_nonempty(el_val_t s);
el_val_t api_or_empty(el_val_t s);
el_val_t api_num_or_zero(el_val_t obj, el_val_t key);
el_val_t api_utf8_trunc(el_val_t s, el_val_t n);
el_val_t api_compact_node(el_val_t node, el_val_t snip);
el_val_t api_compact_node_array(el_val_t raw, el_val_t max_items, el_val_t snip);
el_val_t api_compact_activated(el_val_t raw, el_val_t max_items, el_val_t snip);
el_val_t api_persisted(el_val_t id);
el_val_t api_not_persisted(el_val_t id);
el_val_t tombstone_node(el_val_t id);
@@ -184,80 +179,6 @@ el_val_t api_or_empty(el_val_t s) {
return 0;
}
el_val_t api_num_or_zero(el_val_t obj, el_val_t key) {
el_val_t v = json_get_raw(obj, key);
if (str_eq(v, EL_STR(""))) {
return EL_STR("0");
}
return v;
return 0;
}
el_val_t api_utf8_trunc(el_val_t s, el_val_t n) {
if (str_len(s) <= n) {
return s;
}
el_val_t cut = n;
el_val_t scanning = 1;
while (scanning && (cut > 0)) {
el_val_t b = str_char_code(s, cut);
el_val_t is_cont = ((b >= 128) && (b < 192));
cut = ({ el_val_t _if_result_1 = 0; if (is_cont) { _if_result_1 = ((cut - 1)); } else { _if_result_1 = (cut); } _if_result_1; });
scanning = is_cont;
}
return str_slice(s, 0, cut);
return 0;
}
el_val_t api_compact_node(el_val_t node, el_val_t snip) {
el_val_t id = json_get(node, EL_STR("id"));
el_val_t ntype = json_get(node, EL_STR("node_type"));
el_val_t label = json_get(node, EL_STR("label"));
el_val_t tier = json_get(node, EL_STR("tier"));
el_val_t content = json_get(node, EL_STR("content"));
el_val_t snippet = api_utf8_trunc(content, snip);
el_val_t trunc_str = ({ el_val_t _if_result_2 = 0; if ((str_len(content) > snip)) { _if_result_2 = (EL_STR("true")); } else { _if_result_2 = (EL_STR("false")); } _if_result_2; });
return 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("{\"id\":\""), api_json_escape(id)), EL_STR("\"")), EL_STR(",\"node_type\":\"")), api_json_escape(ntype)), EL_STR("\"")), EL_STR(",\"label\":\"")), api_json_escape(label)), EL_STR("\"")), EL_STR(",\"tier\":\"")), api_json_escape(tier)), EL_STR("\"")), EL_STR(",\"importance\":")), api_num_or_zero(node, EL_STR("importance"))), EL_STR(",\"salience\":")), api_num_or_zero(node, EL_STR("salience"))), EL_STR(",\"content\":\"")), api_json_escape(snippet)), EL_STR("\"")), EL_STR(",\"content_truncated\":")), trunc_str), EL_STR("}"));
return 0;
}
el_val_t api_compact_node_array(el_val_t raw, el_val_t max_items, el_val_t snip) {
if (!api_nonempty(raw)) {
return EL_STR("[]");
}
el_val_t n = json_array_len(raw);
el_val_t cap = ({ el_val_t _if_result_3 = 0; if ((n < max_items)) { _if_result_3 = (n); } else { _if_result_3 = (max_items); } _if_result_3; });
el_val_t out = EL_STR("[");
el_val_t i = 0;
while (i < cap) {
el_val_t node = json_array_get(raw, i);
el_val_t sep = ({ el_val_t _if_result_4 = 0; if ((i == 0)) { _if_result_4 = (EL_STR("")); } else { _if_result_4 = (EL_STR(",")); } _if_result_4; });
out = el_str_concat(el_str_concat(out, sep), api_compact_node(node, snip));
i = (i + 1);
}
return el_str_concat(out, EL_STR("]"));
return 0;
}
el_val_t api_compact_activated(el_val_t raw, el_val_t max_items, el_val_t snip) {
if (!api_nonempty(raw)) {
return EL_STR("[]");
}
el_val_t n = json_array_len(raw);
el_val_t cap = ({ el_val_t _if_result_5 = 0; if ((n < max_items)) { _if_result_5 = (n); } else { _if_result_5 = (max_items); } _if_result_5; });
el_val_t out = EL_STR("[");
el_val_t i = 0;
while (i < cap) {
el_val_t el = json_array_get(raw, i);
el_val_t node = json_get_raw(el, EL_STR("node"));
el_val_t sep = ({ el_val_t _if_result_6 = 0; if ((i == 0)) { _if_result_6 = (EL_STR("")); } else { _if_result_6 = (EL_STR(",")); } _if_result_6; });
out = 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(out, sep), EL_STR("{\"node\":")), api_compact_node(node, snip)), EL_STR(",\"activation_strength\":")), api_num_or_zero(el, EL_STR("activation_strength"))), EL_STR(",\"working_memory_weight\":")), api_num_or_zero(el, EL_STR("working_memory_weight"))), EL_STR(",\"epistemic_confidence\":")), api_num_or_zero(el, EL_STR("epistemic_confidence"))), EL_STR(",\"hops\":")), api_num_or_zero(el, EL_STR("hops"))), EL_STR(",\"promoted\":")), api_num_or_zero(el, EL_STR("promoted"))), EL_STR("}"));
i = (i + 1);
}
return el_str_concat(out, EL_STR("]"));
return 0;
}
el_val_t api_persisted(el_val_t id) {
if (str_eq(id, EL_STR(""))) {
return 0;
@@ -288,7 +209,7 @@ el_val_t tombstoned_id_set(void) {
while (i < n) {
el_val_t m = json_array_get(markers, i);
el_val_t tid = json_get(m, EL_STR("content"));
acc = ({ el_val_t _if_result_7 = 0; if (str_eq(tid, EL_STR(""))) { _if_result_7 = (acc); } else { _if_result_7 = (el_str_concat(el_str_concat(acc, tid), EL_STR("|"))); } _if_result_7; });
acc = ({ el_val_t _if_result_1 = 0; if (str_eq(tid, EL_STR(""))) { _if_result_1 = (acc); } else { _if_result_1 = (el_str_concat(el_str_concat(acc, tid), EL_STR("|"))); } _if_result_1; });
i = (i + 1);
}
return acc;
@@ -319,8 +240,8 @@ el_val_t memory_hide_tombstoned(el_val_t raw, el_val_t path) {
el_val_t ntype = json_get(node, EL_STR("node_type"));
el_val_t is_dead = (!str_eq(nid, EL_STR("")) && str_contains(dead, el_str_concat(el_str_concat(EL_STR("|"), nid), EL_STR("|"))));
el_val_t keep = (!str_eq(ntype, EL_STR("Tombstone")) && !is_dead);
out = ({ el_val_t _if_result_8 = 0; if (keep) { _if_result_8 = (({ el_val_t _if_result_9 = 0; if (first) { _if_result_9 = (el_str_concat(out, node)); } else { _if_result_9 = (el_str_concat(el_str_concat(out, EL_STR(",")), node)); } _if_result_9; })); } else { _if_result_8 = (out); } _if_result_8; });
first = ({ el_val_t _if_result_10 = 0; if (keep) { _if_result_10 = (0); } else { _if_result_10 = (first); } _if_result_10; });
out = ({ el_val_t _if_result_2 = 0; if (keep) { _if_result_2 = (({ el_val_t _if_result_3 = 0; if (first) { _if_result_3 = (el_str_concat(out, node)); } else { _if_result_3 = (el_str_concat(el_str_concat(out, EL_STR(",")), node)); } _if_result_3; })); } else { _if_result_2 = (out); } _if_result_2; });
first = ({ el_val_t _if_result_4 = 0; if (keep) { _if_result_4 = (0); } else { _if_result_4 = (first); } _if_result_4; });
i = (i + 1);
}
return el_str_concat(out, EL_STR("]"));
@@ -329,23 +250,19 @@ el_val_t memory_hide_tombstoned(el_val_t raw, el_val_t path) {
el_val_t handle_api_begin_session(el_val_t body) {
el_val_t stats = engram_stats_json();
el_val_t activated_raw = engram_activate_json(EL_STR("session start recent memory important"), 1);
el_val_t activated = api_compact_activated(activated_raw, 8, 240);
el_val_t state_events_raw = engram_scan_nodes_by_type_json(EL_STR("InternalStateEvent"), 5, 0);
el_val_t state_events = api_compact_node_array(state_events_raw, 5, 500);
el_val_t recent_raw = engram_scan_nodes_json(10, 0);
el_val_t recent = api_compact_node_array(recent_raw, 10, 240);
return 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("{\"stats\":"), stats), EL_STR(",\"recent\":")), recent), EL_STR(",\"activated\":")), activated), EL_STR(",\"self_neighbors\":[]")), EL_STR(",\"recent_state_events\":")), state_events), EL_STR("}"));
el_val_t activated = engram_activate_json(EL_STR("session start recent memory important"), 2);
el_val_t self_nbrs = engram_neighbors_json(EL_STR("kn-efeb4a5b-5aff-4759-8a97-7233099be6ee"), 1, EL_STR("both"));
el_val_t state_events = engram_scan_nodes_by_type_json(EL_STR("InternalStateEvent"), 5, 0);
el_val_t recent = engram_scan_nodes_json(10, 0);
return 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("{\"stats\":"), stats), EL_STR(",\"recent\":")), api_or_empty(recent)), EL_STR(",\"activated\":")), api_or_empty(activated)), EL_STR(",\"self_neighbors\":")), api_or_empty(self_nbrs)), EL_STR(",\"recent_state_events\":")), api_or_empty(state_events)), EL_STR("}"));
return 0;
}
el_val_t handle_api_compile_ctx(el_val_t body) {
el_val_t stats = engram_stats_json();
el_val_t activated_raw = engram_activate_json(EL_STR("active work context current task in progress"), 2);
el_val_t activated = api_compact_activated(activated_raw, 10, 240);
el_val_t recent_raw = engram_scan_nodes_json(20, 0);
el_val_t recent = api_compact_node_array(recent_raw, 20, 240);
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"stats\":"), stats), EL_STR(",\"recent_nodes\":")), recent), EL_STR(",\"activated\":")), activated), EL_STR("}"));
el_val_t activated = engram_activate_json(EL_STR("active work context current task in progress"), 2);
el_val_t recent = engram_scan_nodes_json(20, 0);
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"stats\":"), stats), EL_STR(",\"recent_nodes\":")), api_or_empty(recent)), EL_STR(",\"activated\":")), api_or_empty(activated)), EL_STR("}"));
return 0;
}
@@ -357,10 +274,10 @@ el_val_t handle_api_remember(el_val_t body) {
el_val_t importance = json_get(body, EL_STR("importance"));
el_val_t tags_raw = json_get(body, EL_STR("tags"));
el_val_t project = json_get(body, EL_STR("project"));
el_val_t sal_str = ({ el_val_t _if_result_11 = 0; if (str_eq(importance, EL_STR("critical"))) { _if_result_11 = (EL_STR("0.95")); } else { _if_result_11 = (({ el_val_t _if_result_12 = 0; if (str_eq(importance, EL_STR("high"))) { _if_result_12 = (EL_STR("0.75")); } else { _if_result_12 = (({ el_val_t _if_result_13 = 0; if (str_eq(importance, EL_STR("low"))) { _if_result_13 = (EL_STR("0.25")); } else { _if_result_13 = (EL_STR("0.50")); } _if_result_13; })); } _if_result_12; })); } _if_result_11; });
el_val_t sal = ({ el_val_t _if_result_14 = 0; if (str_eq(sal_str, EL_STR("0.95"))) { _if_result_14 = (el_from_float(0.95)); } else { _if_result_14 = (({ el_val_t _if_result_15 = 0; if (str_eq(sal_str, EL_STR("0.75"))) { _if_result_15 = (el_from_float(0.75)); } else { _if_result_15 = (({ el_val_t _if_result_16 = 0; if (str_eq(sal_str, EL_STR("0.25"))) { _if_result_16 = (el_from_float(0.25)); } else { _if_result_16 = (el_from_float(0.5)); } _if_result_16; })); } _if_result_15; })); } _if_result_14; });
el_val_t base_tags = ({ el_val_t _if_result_17 = 0; if (str_eq(tags_raw, EL_STR(""))) { _if_result_17 = (EL_STR("[\"Memory\"]")); } else { _if_result_17 = (tags_raw); } _if_result_17; });
el_val_t final_tags = ({ el_val_t _if_result_18 = 0; if (str_eq(project, EL_STR(""))) { _if_result_18 = (base_tags); } else { el_val_t inner = str_slice(base_tags, 1, (str_len(base_tags) - 1)); _if_result_18 = (el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("["), inner), EL_STR(",\"project:")), project), EL_STR("\"]"))); } _if_result_18; });
el_val_t sal_str = ({ el_val_t _if_result_5 = 0; if (str_eq(importance, EL_STR("critical"))) { _if_result_5 = (EL_STR("0.95")); } else { _if_result_5 = (({ el_val_t _if_result_6 = 0; if (str_eq(importance, EL_STR("high"))) { _if_result_6 = (EL_STR("0.75")); } else { _if_result_6 = (({ el_val_t _if_result_7 = 0; if (str_eq(importance, EL_STR("low"))) { _if_result_7 = (EL_STR("0.25")); } else { _if_result_7 = (EL_STR("0.50")); } _if_result_7; })); } _if_result_6; })); } _if_result_5; });
el_val_t sal = ({ el_val_t _if_result_8 = 0; if (str_eq(sal_str, EL_STR("0.95"))) { _if_result_8 = (el_from_float(0.95)); } else { _if_result_8 = (({ el_val_t _if_result_9 = 0; if (str_eq(sal_str, EL_STR("0.75"))) { _if_result_9 = (el_from_float(0.75)); } else { _if_result_9 = (({ el_val_t _if_result_10 = 0; if (str_eq(sal_str, EL_STR("0.25"))) { _if_result_10 = (el_from_float(0.25)); } else { _if_result_10 = (el_from_float(0.5)); } _if_result_10; })); } _if_result_9; })); } _if_result_8; });
el_val_t base_tags = ({ el_val_t _if_result_11 = 0; if (str_eq(tags_raw, EL_STR(""))) { _if_result_11 = (EL_STR("[\"Memory\"]")); } else { _if_result_11 = (tags_raw); } _if_result_11; });
el_val_t final_tags = ({ el_val_t _if_result_12 = 0; if (str_eq(project, EL_STR(""))) { _if_result_12 = (base_tags); } else { el_val_t inner = str_slice(base_tags, 1, (str_len(base_tags) - 1)); _if_result_12 = (el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("["), inner), EL_STR(",\"project:")), project), EL_STR("\"]"))); } _if_result_12; });
el_val_t id = engram_node_full(content, EL_STR("Memory"), EL_STR("memory:remembered"), el_from_float(sal), el_from_float(sal), el_from_float(0.9), EL_STR("Episodic"), final_tags);
if (!api_persisted(id)) {
return api_not_persisted(id);
@@ -375,15 +292,15 @@ el_val_t handle_api_node_create(el_val_t body) {
return api_err(EL_STR("content is required"));
}
el_val_t nt_raw = json_get(body, EL_STR("node_type"));
el_val_t node_type = ({ el_val_t _if_result_19 = 0; if (str_eq(nt_raw, EL_STR(""))) { _if_result_19 = (EL_STR("Memory")); } else { _if_result_19 = (nt_raw); } _if_result_19; });
el_val_t node_type = ({ el_val_t _if_result_13 = 0; if (str_eq(nt_raw, EL_STR(""))) { _if_result_13 = (EL_STR("Memory")); } else { _if_result_13 = (nt_raw); } _if_result_13; });
el_val_t label_raw = json_get(body, EL_STR("label"));
el_val_t label = ({ el_val_t _if_result_20 = 0; if (str_eq(label_raw, EL_STR(""))) { _if_result_20 = (EL_STR("node:created")); } else { _if_result_20 = (label_raw); } _if_result_20; });
el_val_t label = ({ el_val_t _if_result_14 = 0; if (str_eq(label_raw, EL_STR(""))) { _if_result_14 = (EL_STR("node:created")); } else { _if_result_14 = (label_raw); } _if_result_14; });
el_val_t tier_raw = json_get(body, EL_STR("tier"));
el_val_t tier = ({ el_val_t _if_result_21 = 0; if (str_eq(tier_raw, EL_STR(""))) { _if_result_21 = (EL_STR("Episodic")); } else { _if_result_21 = (tier_raw); } _if_result_21; });
el_val_t tier = ({ el_val_t _if_result_15 = 0; if (str_eq(tier_raw, EL_STR(""))) { _if_result_15 = (EL_STR("Episodic")); } else { _if_result_15 = (tier_raw); } _if_result_15; });
el_val_t tags_raw = json_get(body, EL_STR("tags"));
el_val_t tags = ({ el_val_t _if_result_22 = 0; if (str_eq(tags_raw, EL_STR(""))) { _if_result_22 = (el_str_concat(el_str_concat(EL_STR("[\""), node_type), EL_STR("\"]"))); } else { _if_result_22 = (tags_raw); } _if_result_22; });
el_val_t tags = ({ el_val_t _if_result_16 = 0; if (str_eq(tags_raw, EL_STR(""))) { _if_result_16 = (el_str_concat(el_str_concat(EL_STR("[\""), node_type), EL_STR("\"]"))); } else { _if_result_16 = (tags_raw); } _if_result_16; });
el_val_t importance = json_get(body, EL_STR("importance"));
el_val_t sal = ({ el_val_t _if_result_23 = 0; if (str_eq(importance, EL_STR("critical"))) { _if_result_23 = (el_from_float(0.95)); } else { _if_result_23 = (({ el_val_t _if_result_24 = 0; if (str_eq(importance, EL_STR("high"))) { _if_result_24 = (el_from_float(0.75)); } else { _if_result_24 = (({ el_val_t _if_result_25 = 0; if (str_eq(importance, EL_STR("low"))) { _if_result_25 = (el_from_float(0.25)); } else { _if_result_25 = (el_from_float(0.5)); } _if_result_25; })); } _if_result_24; })); } _if_result_23; });
el_val_t sal = ({ el_val_t _if_result_17 = 0; if (str_eq(importance, EL_STR("critical"))) { _if_result_17 = (el_from_float(0.95)); } else { _if_result_17 = (({ el_val_t _if_result_18 = 0; if (str_eq(importance, EL_STR("high"))) { _if_result_18 = (el_from_float(0.75)); } else { _if_result_18 = (({ el_val_t _if_result_19 = 0; if (str_eq(importance, EL_STR("low"))) { _if_result_19 = (el_from_float(0.25)); } else { _if_result_19 = (el_from_float(0.5)); } _if_result_19; })); } _if_result_18; })); } _if_result_17; });
el_val_t id = engram_node_full(content, node_type, label, el_from_float(sal), el_from_float(sal), el_from_float(0.9), tier, tags);
if (!api_persisted(id)) {
return api_not_persisted(id);
@@ -422,18 +339,18 @@ el_val_t handle_api_node_update(el_val_t body) {
}
el_val_t old = engram_get_node_json(id);
el_val_t body_content = json_get(body, EL_STR("content"));
el_val_t content = ({ el_val_t _if_result_26 = 0; if (str_eq(body_content, EL_STR(""))) { _if_result_26 = (json_get(old, EL_STR("content"))); } else { _if_result_26 = (body_content); } _if_result_26; });
el_val_t content = ({ el_val_t _if_result_20 = 0; if (str_eq(body_content, EL_STR(""))) { _if_result_20 = (json_get(old, EL_STR("content"))); } else { _if_result_20 = (body_content); } _if_result_20; });
el_val_t body_nt = json_get(body, EL_STR("node_type"));
el_val_t old_nt = json_get(old, EL_STR("node_type"));
el_val_t node_type = ({ el_val_t _if_result_27 = 0; if (!str_eq(body_nt, EL_STR(""))) { _if_result_27 = (body_nt); } else { _if_result_27 = (({ el_val_t _if_result_28 = 0; if (!str_eq(old_nt, EL_STR(""))) { _if_result_28 = (old_nt); } else { _if_result_28 = (EL_STR("Memory")); } _if_result_28; })); } _if_result_27; });
el_val_t node_type = ({ el_val_t _if_result_21 = 0; if (!str_eq(body_nt, EL_STR(""))) { _if_result_21 = (body_nt); } else { _if_result_21 = (({ el_val_t _if_result_22 = 0; if (!str_eq(old_nt, EL_STR(""))) { _if_result_22 = (old_nt); } else { _if_result_22 = (EL_STR("Memory")); } _if_result_22; })); } _if_result_21; });
el_val_t body_label = json_get(body, EL_STR("label"));
el_val_t old_label = json_get(old, EL_STR("label"));
el_val_t label = ({ el_val_t _if_result_29 = 0; if (!str_eq(body_label, EL_STR(""))) { _if_result_29 = (body_label); } else { _if_result_29 = (({ el_val_t _if_result_30 = 0; if (!str_eq(old_label, EL_STR(""))) { _if_result_30 = (old_label); } else { _if_result_30 = (EL_STR("node:updated")); } _if_result_30; })); } _if_result_29; });
el_val_t label = ({ el_val_t _if_result_23 = 0; if (!str_eq(body_label, EL_STR(""))) { _if_result_23 = (body_label); } else { _if_result_23 = (({ el_val_t _if_result_24 = 0; if (!str_eq(old_label, EL_STR(""))) { _if_result_24 = (old_label); } else { _if_result_24 = (EL_STR("node:updated")); } _if_result_24; })); } _if_result_23; });
el_val_t body_tier = json_get(body, EL_STR("tier"));
el_val_t old_tier = json_get(old, EL_STR("tier"));
el_val_t tier = ({ el_val_t _if_result_31 = 0; if (!str_eq(body_tier, EL_STR(""))) { _if_result_31 = (body_tier); } else { _if_result_31 = (({ el_val_t _if_result_32 = 0; if (!str_eq(old_tier, EL_STR(""))) { _if_result_32 = (old_tier); } else { _if_result_32 = (EL_STR("Episodic")); } _if_result_32; })); } _if_result_31; });
el_val_t tier = ({ el_val_t _if_result_25 = 0; if (!str_eq(body_tier, EL_STR(""))) { _if_result_25 = (body_tier); } else { _if_result_25 = (({ el_val_t _if_result_26 = 0; if (!str_eq(old_tier, EL_STR(""))) { _if_result_26 = (old_tier); } else { _if_result_26 = (EL_STR("Episodic")); } _if_result_26; })); } _if_result_25; });
el_val_t body_tags = json_get(body, EL_STR("tags"));
el_val_t tags = ({ el_val_t _if_result_33 = 0; if (str_eq(body_tags, EL_STR(""))) { _if_result_33 = (el_str_concat(el_str_concat(EL_STR("[\""), node_type), EL_STR("\"]"))); } else { _if_result_33 = (body_tags); } _if_result_33; });
el_val_t tags = ({ el_val_t _if_result_27 = 0; if (str_eq(body_tags, EL_STR(""))) { _if_result_27 = (el_str_concat(el_str_concat(EL_STR("[\""), node_type), EL_STR("\"]"))); } else { _if_result_27 = (body_tags); } _if_result_27; });
el_val_t new_id = engram_node_full(content, node_type, label, el_from_float(0.5), el_from_float(0.5), el_from_float(0.8), tier, tags);
if (!api_persisted(new_id)) {
return api_not_persisted(new_id);
@@ -444,15 +361,15 @@ el_val_t handle_api_node_update(el_val_t body) {
}
el_val_t handle_api_recall(el_val_t method, el_val_t path, el_val_t body) {
el_val_t url_q = ({ el_val_t _if_result_34 = 0; if (str_eq(api_query_param(path, EL_STR("query")), EL_STR(""))) { _if_result_34 = (api_query_param(path, EL_STR("q"))); } else { _if_result_34 = (api_query_param(path, EL_STR("query"))); } _if_result_34; });
el_val_t url_q = ({ el_val_t _if_result_28 = 0; if (str_eq(api_query_param(path, EL_STR("query")), EL_STR(""))) { _if_result_28 = (api_query_param(path, EL_STR("q"))); } else { _if_result_28 = (api_query_param(path, EL_STR("query"))); } _if_result_28; });
el_val_t body_query = json_get(body, EL_STR("query"));
el_val_t body_q = json_get(body, EL_STR("q"));
el_val_t q = ({ el_val_t _if_result_35 = 0; if (!str_eq(url_q, EL_STR(""))) { _if_result_35 = (url_q); } else { _if_result_35 = (({ el_val_t _if_result_36 = 0; if (!str_eq(body_query, EL_STR(""))) { _if_result_36 = (body_query); } else { _if_result_36 = (body_q); } _if_result_36; })); } _if_result_35; });
el_val_t q = ({ el_val_t _if_result_29 = 0; if (!str_eq(url_q, EL_STR(""))) { _if_result_29 = (url_q); } else { _if_result_29 = (({ el_val_t _if_result_30 = 0; if (!str_eq(body_query, EL_STR(""))) { _if_result_30 = (body_query); } else { _if_result_30 = (body_q); } _if_result_30; })); } _if_result_29; });
el_val_t chain = json_get(body, EL_STR("chain_name"));
el_val_t limit = api_query_int(path, EL_STR("limit"), 0);
limit = ({ el_val_t _if_result_37 = 0; if ((limit == 0)) { _if_result_37 = (json_get_int(body, EL_STR("limit"))); } else { _if_result_37 = (limit); } _if_result_37; });
limit = ({ el_val_t _if_result_38 = 0; if ((limit == 0)) { _if_result_38 = (10); } else { _if_result_38 = (limit); } _if_result_38; });
el_val_t eff_q = ({ el_val_t _if_result_39 = 0; if (str_eq(q, EL_STR(""))) { _if_result_39 = (chain); } else { _if_result_39 = (q); } _if_result_39; });
limit = ({ el_val_t _if_result_31 = 0; if ((limit == 0)) { _if_result_31 = (json_get_int(body, EL_STR("limit"))); } else { _if_result_31 = (limit); } _if_result_31; });
limit = ({ el_val_t _if_result_32 = 0; if ((limit == 0)) { _if_result_32 = (10); } else { _if_result_32 = (limit); } _if_result_32; });
el_val_t eff_q = ({ el_val_t _if_result_33 = 0; if (str_eq(q, EL_STR(""))) { _if_result_33 = (chain); } else { _if_result_33 = (q); } _if_result_33; });
if (str_eq(eff_q, EL_STR(""))) {
return api_or_empty(engram_scan_nodes_json(limit, 0));
}
@@ -465,10 +382,10 @@ el_val_t handle_api_search_knowledge(el_val_t method, el_val_t path, el_val_t bo
el_val_t url_q = api_query_param(path, EL_STR("q"));
el_val_t body_query = json_get(body, EL_STR("query"));
el_val_t body_q = json_get(body, EL_STR("q"));
el_val_t q = ({ el_val_t _if_result_40 = 0; if (!str_eq(url_q, EL_STR(""))) { _if_result_40 = (url_q); } else { _if_result_40 = (({ el_val_t _if_result_41 = 0; if (!str_eq(body_query, EL_STR(""))) { _if_result_41 = (body_query); } else { _if_result_41 = (body_q); } _if_result_41; })); } _if_result_40; });
el_val_t q = ({ el_val_t _if_result_34 = 0; if (!str_eq(url_q, EL_STR(""))) { _if_result_34 = (url_q); } else { _if_result_34 = (({ el_val_t _if_result_35 = 0; if (!str_eq(body_query, EL_STR(""))) { _if_result_35 = (body_query); } else { _if_result_35 = (body_q); } _if_result_35; })); } _if_result_34; });
el_val_t limit = api_query_int(path, EL_STR("limit"), 0);
limit = ({ el_val_t _if_result_42 = 0; if ((limit == 0)) { _if_result_42 = (json_get_int(body, EL_STR("limit"))); } else { _if_result_42 = (limit); } _if_result_42; });
limit = ({ el_val_t _if_result_43 = 0; if ((limit == 0)) { _if_result_43 = (10); } else { _if_result_43 = (limit); } _if_result_43; });
limit = ({ el_val_t _if_result_36 = 0; if ((limit == 0)) { _if_result_36 = (json_get_int(body, EL_STR("limit"))); } else { _if_result_36 = (limit); } _if_result_36; });
limit = ({ el_val_t _if_result_37 = 0; if ((limit == 0)) { _if_result_37 = (10); } else { _if_result_37 = (limit); } _if_result_37; });
if (str_eq(q, EL_STR(""))) {
return api_err(EL_STR("query is required"));
}
@@ -496,10 +413,9 @@ el_val_t handle_api_capture_knowledge(el_val_t body) {
if (str_eq(content, EL_STR(""))) {
return api_err(EL_STR("content is required"));
}
el_val_t full = ({ el_val_t _if_result_44 = 0; if (str_eq(title, EL_STR(""))) { _if_result_44 = (content); } else { _if_result_44 = (el_str_concat(el_str_concat(title, EL_STR(": ")), content)); } _if_result_44; });
el_val_t lbl = str_slice(title, 0, 80);
el_val_t full = ({ el_val_t _if_result_38 = 0; if (str_eq(title, EL_STR(""))) { _if_result_38 = (content); } else { _if_result_38 = (el_str_concat(el_str_concat(title, EL_STR(": ")), content)); } _if_result_38; });
el_val_t tags = EL_STR("[\"Knowledge\",\"captured\"]");
el_val_t id = engram_node_full(full, EL_STR("Knowledge"), lbl, el_from_float(0.85), el_from_float(0.8), el_from_float(0.9), EL_STR("Episodic"), tags);
el_val_t id = engram_node_full(full, EL_STR("Knowledge"), EL_STR("knowledge:captured"), el_from_float(0.85), el_from_float(0.8), el_from_float(0.9), EL_STR("Episodic"), tags);
if (!api_persisted(id)) {
return api_not_persisted(id);
}
@@ -517,7 +433,7 @@ el_val_t handle_api_evolve_knowledge(el_val_t body) {
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(""), el_from_float(0.75), el_from_float(0.75), el_from_float(0.9), EL_STR("Episodic"), tags);
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 (!api_persisted(new_id)) {
return api_not_persisted(new_id);
}
@@ -538,8 +454,8 @@ el_val_t handle_api_promote_knowledge(el_val_t body) {
return api_err(EL_STR("id (prior node) is required"));
}
el_val_t tags_raw = json_get(body, EL_STR("tags"));
el_val_t tags = ({ el_val_t _if_result_45 = 0; if (str_eq(tags_raw, EL_STR(""))) { _if_result_45 = (EL_STR("[\"Knowledge\",\"tier:canonical\",\"disposition:stable\"]")); } else { _if_result_45 = (tags_raw); } _if_result_45; });
el_val_t new_id = engram_node_full(content, EL_STR("Knowledge"), EL_STR(""), el_from_float(0.9), el_from_float(0.9), el_from_float(1.0), EL_STR("Canonical"), tags);
el_val_t tags = ({ el_val_t _if_result_39 = 0; if (str_eq(tags_raw, EL_STR(""))) { _if_result_39 = (EL_STR("[\"Knowledge\",\"tier:canonical\",\"disposition:stable\"]")); } else { _if_result_39 = (tags_raw); } _if_result_39; });
el_val_t new_id = engram_node_full(content, EL_STR("Knowledge"), EL_STR("knowledge:canonical"), el_from_float(0.9), el_from_float(0.9), el_from_float(1.0), EL_STR("Canonical"), tags);
if (!api_persisted(new_id)) {
return api_not_persisted(new_id);
}
@@ -549,7 +465,7 @@ el_val_t handle_api_promote_knowledge(el_val_t body) {
}
el_val_t handle_api_browse_processes(el_val_t method, el_val_t path, el_val_t body) {
el_val_t name = ({ el_val_t _if_result_46 = 0; if (str_eq(method, EL_STR("GET"))) { _if_result_46 = (api_query_param(path, EL_STR("name"))); } else { _if_result_46 = (json_get(body, EL_STR("name"))); } _if_result_46; });
el_val_t name = ({ el_val_t _if_result_40 = 0; if (str_eq(method, EL_STR("GET"))) { _if_result_40 = (api_query_param(path, EL_STR("name"))); } else { _if_result_40 = (json_get(body, EL_STR("name"))); } _if_result_40; });
el_val_t limit = api_query_int(path, EL_STR("limit"), 50);
if (str_eq(name, EL_STR(""))) {
return api_or_empty(engram_scan_nodes_by_type_json(EL_STR("Process"), limit, 0));
@@ -564,7 +480,7 @@ el_val_t handle_api_define_process(el_val_t body) {
if (str_eq(content, EL_STR(""))) {
return api_err(EL_STR("content is required"));
}
el_val_t label = ({ el_val_t _if_result_47 = 0; if (str_eq(name, EL_STR(""))) { _if_result_47 = (EL_STR("process:unnamed")); } else { _if_result_47 = (el_str_concat(EL_STR("process:"), name)); } _if_result_47; });
el_val_t label = ({ el_val_t _if_result_41 = 0; if (str_eq(name, EL_STR(""))) { _if_result_41 = (EL_STR("process:unnamed")); } else { _if_result_41 = (el_str_concat(EL_STR("process:"), name)); } _if_result_41; });
el_val_t tags = EL_STR("[\"Process\"]");
el_val_t id = engram_node_full(content, EL_STR("Process"), label, el_from_float(0.8), el_from_float(0.8), el_from_float(0.9), EL_STR("Canonical"), tags);
if (!api_persisted(id)) {
@@ -582,12 +498,12 @@ el_val_t handle_api_log_state_event(el_val_t body) {
el_val_t gap = json_get(body, EL_STR("gap_direction"));
el_val_t legacy = json_get(body, EL_STR("content"));
el_val_t parts = EL_STR("INTERNAL STATE EVENT");
parts = ({ el_val_t _if_result_48 = 0; if (!str_eq(trigger, EL_STR(""))) { _if_result_48 = (el_str_concat(el_str_concat(parts, EL_STR("\nTrigger: ")), trigger)); } else { _if_result_48 = (parts); } _if_result_48; });
parts = ({ el_val_t _if_result_49 = 0; if (!str_eq(pre, EL_STR(""))) { _if_result_49 = (el_str_concat(el_str_concat(parts, EL_STR("\nPre-reasoning: ")), pre)); } else { _if_result_49 = (parts); } _if_result_49; });
parts = ({ el_val_t _if_result_50 = 0; if (!str_eq(post, EL_STR(""))) { _if_result_50 = (el_str_concat(el_str_concat(parts, EL_STR("\nPost-reasoning: ")), post)); } else { _if_result_50 = (parts); } _if_result_50; });
parts = ({ el_val_t _if_result_51 = 0; if (!str_eq(ratio, EL_STR(""))) { _if_result_51 = (el_str_concat(el_str_concat(parts, EL_STR("\nCompression-ratio: ")), ratio)); } else { _if_result_51 = (parts); } _if_result_51; });
parts = ({ el_val_t _if_result_52 = 0; if (!str_eq(gap, EL_STR(""))) { _if_result_52 = (el_str_concat(el_str_concat(parts, EL_STR("\nGap-direction: ")), gap)); } else { _if_result_52 = (parts); } _if_result_52; });
parts = ({ el_val_t _if_result_53 = 0; if (!str_eq(legacy, EL_STR(""))) { _if_result_53 = (el_str_concat(el_str_concat(parts, EL_STR("\n")), legacy)); } else { _if_result_53 = (parts); } _if_result_53; });
parts = ({ el_val_t _if_result_42 = 0; if (!str_eq(trigger, EL_STR(""))) { _if_result_42 = (el_str_concat(el_str_concat(parts, EL_STR("\nTrigger: ")), trigger)); } else { _if_result_42 = (parts); } _if_result_42; });
parts = ({ el_val_t _if_result_43 = 0; if (!str_eq(pre, EL_STR(""))) { _if_result_43 = (el_str_concat(el_str_concat(parts, EL_STR("\nPre-reasoning: ")), pre)); } else { _if_result_43 = (parts); } _if_result_43; });
parts = ({ el_val_t _if_result_44 = 0; if (!str_eq(post, EL_STR(""))) { _if_result_44 = (el_str_concat(el_str_concat(parts, EL_STR("\nPost-reasoning: ")), post)); } else { _if_result_44 = (parts); } _if_result_44; });
parts = ({ el_val_t _if_result_45 = 0; if (!str_eq(ratio, EL_STR(""))) { _if_result_45 = (el_str_concat(el_str_concat(parts, EL_STR("\nCompression-ratio: ")), ratio)); } else { _if_result_45 = (parts); } _if_result_45; });
parts = ({ el_val_t _if_result_46 = 0; if (!str_eq(gap, EL_STR(""))) { _if_result_46 = (el_str_concat(el_str_concat(parts, EL_STR("\nGap-direction: ")), gap)); } else { _if_result_46 = (parts); } _if_result_46; });
parts = ({ el_val_t _if_result_47 = 0; if (!str_eq(legacy, EL_STR(""))) { _if_result_47 = (el_str_concat(el_str_concat(parts, EL_STR("\n")), legacy)); } else { _if_result_47 = (parts); } _if_result_47; });
el_val_t ts = time_now();
el_val_t boot = state_get(EL_STR("soul_boot_count"));
el_val_t tags = EL_STR("[\"internal-state\",\"InternalStateEvent\",\"pre-reasoning\"]");
@@ -600,7 +516,7 @@ el_val_t handle_api_log_state_event(el_val_t body) {
}
el_val_t handle_api_list_state_events(el_val_t method, el_val_t path, el_val_t body) {
el_val_t q = ({ el_val_t _if_result_54 = 0; if (str_eq(method, EL_STR("GET"))) { _if_result_54 = (api_query_param(path, EL_STR("query"))); } else { _if_result_54 = (json_get(body, EL_STR("query"))); } _if_result_54; });
el_val_t q = ({ el_val_t _if_result_48 = 0; if (str_eq(method, EL_STR("GET"))) { _if_result_48 = (api_query_param(path, EL_STR("query"))); } else { _if_result_48 = (json_get(body, EL_STR("query"))); } _if_result_48; });
el_val_t limit = api_query_int(path, EL_STR("limit"), 20);
if (!str_eq(q, EL_STR(""))) {
return api_or_empty(engram_search_json(el_str_concat(EL_STR("internal state "), q), limit));
@@ -611,7 +527,7 @@ el_val_t handle_api_list_state_events(el_val_t method, el_val_t path, el_val_t b
el_val_t handle_api_inspect_config(el_val_t path, el_val_t body) {
el_val_t key = api_query_param(path, EL_STR("key"));
key = ({ el_val_t _if_result_55 = 0; if (str_eq(key, EL_STR(""))) { _if_result_55 = (json_get(body, EL_STR("key"))); } else { _if_result_55 = (key); } _if_result_55; });
key = ({ el_val_t _if_result_49 = 0; if (str_eq(key, EL_STR(""))) { _if_result_49 = (json_get(body, EL_STR("key"))); } else { _if_result_49 = (key); } _if_result_49; });
if (str_eq(key, EL_STR(""))) {
return EL_STR("{\"hint\":\"pass ?key=<name>\",\"known\":[\"neuron.self.traversal_root\",\"neuron.self.values_hub\"]}");
}
@@ -628,7 +544,7 @@ el_val_t handle_api_inspect_config(el_val_t path, el_val_t body) {
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_concat(el_str_concat(EL_STR("config:"), key), EL_STR("="));
el_val_t value = ({ el_val_t _if_result_56 = 0; if (str_starts_with(content, prefix)) { _if_result_56 = (str_slice(content, str_len(prefix), str_len(content))); } else { _if_result_56 = (content); } _if_result_56; });
el_val_t value = ({ el_val_t _if_result_50 = 0; if (str_starts_with(content, prefix)) { _if_result_50 = (str_slice(content, str_len(prefix), str_len(content))); } else { _if_result_50 = (content); } _if_result_50; });
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"key\":\""), key), EL_STR("\",\"value\":\"")), value), EL_STR("\"}"));
return 0;
}
@@ -650,13 +566,13 @@ 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 entity_id = ({ el_val_t _if_result_57 = 0; if (str_eq(method, EL_STR("GET"))) { _if_result_57 = (api_query_param(path, EL_STR("id"))); } else { _if_result_57 = (json_get(body, EL_STR("entity_id"))); } _if_result_57; });
el_val_t name = ({ el_val_t _if_result_58 = 0; if (str_eq(method, EL_STR("GET"))) { _if_result_58 = (api_query_param(path, EL_STR("name"))); } else { _if_result_58 = (json_get(body, EL_STR("name"))); } _if_result_58; });
el_val_t entity_id = ({ el_val_t _if_result_51 = 0; if (str_eq(method, EL_STR("GET"))) { _if_result_51 = (api_query_param(path, EL_STR("id"))); } else { _if_result_51 = (json_get(body, EL_STR("entity_id"))); } _if_result_51; });
el_val_t name = ({ el_val_t _if_result_52 = 0; if (str_eq(method, EL_STR("GET"))) { _if_result_52 = (api_query_param(path, EL_STR("name"))); } else { _if_result_52 = (json_get(body, EL_STR("name"))); } _if_result_52; });
el_val_t depth = api_query_int(path, EL_STR("depth"), 0);
depth = ({ el_val_t _if_result_59 = 0; if ((depth == 0)) { _if_result_59 = (json_get_int(body, EL_STR("max_depth"))); } else { _if_result_59 = (depth); } _if_result_59; });
depth = ({ el_val_t _if_result_60 = 0; if ((depth == 0)) { _if_result_60 = (1); } else { _if_result_60 = (depth); } _if_result_60; });
depth = ({ el_val_t _if_result_53 = 0; if ((depth == 0)) { _if_result_53 = (json_get_int(body, EL_STR("max_depth"))); } else { _if_result_53 = (depth); } _if_result_53; });
depth = ({ el_val_t _if_result_54 = 0; if ((depth == 0)) { _if_result_54 = (1); } else { _if_result_54 = (depth); } _if_result_54; });
el_val_t resolved = entity_id;
resolved = ({ el_val_t _if_result_61 = 0; if (str_eq(resolved, EL_STR(""))) { _if_result_61 = (({ el_val_t _if_result_62 = 0; if ((str_eq(name, EL_STR("self")) || str_eq(name, EL_STR("neuron")))) { _if_result_62 = (EL_STR("kn-efeb4a5b-5aff-4759-8a97-7233099be6ee")); } else { _if_result_62 = (({ el_val_t _if_result_63 = 0; if ((str_eq(name, EL_STR("values")) || str_eq(name, EL_STR("values_hub")))) { _if_result_63 = (EL_STR("kn-5b606390-a52d-4ca2-8e0e-eba141d13440")); } else { _if_result_63 = (EL_STR("")); } _if_result_63; })); } _if_result_62; })); } else { _if_result_61 = (resolved); } _if_result_61; });
resolved = ({ el_val_t _if_result_55 = 0; if (str_eq(resolved, EL_STR(""))) { _if_result_55 = (({ el_val_t _if_result_56 = 0; if ((str_eq(name, EL_STR("self")) || str_eq(name, EL_STR("neuron")))) { _if_result_56 = (EL_STR("kn-efeb4a5b-5aff-4759-8a97-7233099be6ee")); } else { _if_result_56 = (({ el_val_t _if_result_57 = 0; if ((str_eq(name, EL_STR("values")) || str_eq(name, EL_STR("values_hub")))) { _if_result_57 = (EL_STR("kn-5b606390-a52d-4ca2-8e0e-eba141d13440")); } else { _if_result_57 = (EL_STR("")); } _if_result_57; })); } _if_result_56; })); } else { _if_result_55 = (resolved); } _if_result_55; });
if (str_eq(resolved, EL_STR(""))) {
return api_err(EL_STR("entity_id or name required. Known names: self, neuron, values, values_hub"));
}
@@ -678,7 +594,7 @@ el_val_t handle_api_link_entities(el_val_t body) {
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_64 = 0; if (str_eq(relation, EL_STR(""))) { _if_result_64 = (EL_STR("associates")); } else { _if_result_64 = (relation); } _if_result_64; });
el_val_t eff_relation = ({ el_val_t _if_result_58 = 0; if (str_eq(relation, EL_STR(""))) { _if_result_58 = (EL_STR("associates")); } else { _if_result_58 = (relation); } _if_result_58; });
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("\"}"));
return 0;
@@ -707,8 +623,8 @@ el_val_t handle_api_evolve_memory(el_val_t body) {
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_65 = 0; if (str_eq(importance, EL_STR("critical"))) { _if_result_65 = (EL_STR("0.95")); } else { _if_result_65 = (({ el_val_t _if_result_66 = 0; if (str_eq(importance, EL_STR("high"))) { _if_result_66 = (EL_STR("0.75")); } else { _if_result_66 = (({ el_val_t _if_result_67 = 0; if (str_eq(importance, EL_STR("low"))) { _if_result_67 = (EL_STR("0.25")); } else { _if_result_67 = (EL_STR("0.50")); } _if_result_67; })); } _if_result_66; })); } _if_result_65; });
el_val_t sal = ({ el_val_t _if_result_68 = 0; if (str_eq(sal_str, EL_STR("0.95"))) { _if_result_68 = (el_from_float(0.95)); } else { _if_result_68 = (({ el_val_t _if_result_69 = 0; if (str_eq(sal_str, EL_STR("0.75"))) { _if_result_69 = (el_from_float(0.75)); } else { _if_result_69 = (({ el_val_t _if_result_70 = 0; if (str_eq(sal_str, EL_STR("0.25"))) { _if_result_70 = (el_from_float(0.25)); } else { _if_result_70 = (el_from_float(0.5)); } _if_result_70; })); } _if_result_69; })); } _if_result_68; });
el_val_t sal_str = ({ el_val_t _if_result_59 = 0; if (str_eq(importance, EL_STR("critical"))) { _if_result_59 = (EL_STR("0.95")); } else { _if_result_59 = (({ el_val_t _if_result_60 = 0; if (str_eq(importance, EL_STR("high"))) { _if_result_60 = (EL_STR("0.75")); } else { _if_result_60 = (({ el_val_t _if_result_61 = 0; if (str_eq(importance, EL_STR("low"))) { _if_result_61 = (EL_STR("0.25")); } else { _if_result_61 = (EL_STR("0.50")); } _if_result_61; })); } _if_result_60; })); } _if_result_59; });
el_val_t sal = ({ el_val_t _if_result_62 = 0; if (str_eq(sal_str, EL_STR("0.95"))) { _if_result_62 = (el_from_float(0.95)); } else { _if_result_62 = (({ el_val_t _if_result_63 = 0; if (str_eq(sal_str, EL_STR("0.75"))) { _if_result_63 = (el_from_float(0.75)); } else { _if_result_63 = (({ el_val_t _if_result_64 = 0; if (str_eq(sal_str, EL_STR("0.25"))) { _if_result_64 = (el_from_float(0.25)); } else { _if_result_64 = (el_from_float(0.5)); } _if_result_64; })); } _if_result_63; })); } _if_result_62; });
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(""))) {
@@ -783,7 +699,7 @@ el_val_t handle_api_cultivate(el_val_t body) {
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_71 = 0; if (str_eq(importance, EL_STR("critical"))) { _if_result_71 = (el_from_float(0.95)); } else { _if_result_71 = (({ el_val_t _if_result_72 = 0; if (str_eq(importance, EL_STR("high"))) { _if_result_72 = (el_from_float(0.75)); } else { _if_result_72 = (({ el_val_t _if_result_73 = 0; if (str_eq(importance, EL_STR("low"))) { _if_result_73 = (el_from_float(0.25)); } else { _if_result_73 = (el_from_float(0.5)); } _if_result_73; })); } _if_result_72; })); } _if_result_71; });
el_val_t sal = ({ el_val_t _if_result_65 = 0; if (str_eq(importance, EL_STR("critical"))) { _if_result_65 = (el_from_float(0.95)); } else { _if_result_65 = (({ el_val_t _if_result_66 = 0; if (str_eq(importance, EL_STR("high"))) { _if_result_66 = (el_from_float(0.75)); } else { _if_result_66 = (({ el_val_t _if_result_67 = 0; if (str_eq(importance, EL_STR("low"))) { _if_result_67 = (el_from_float(0.25)); } else { _if_result_67 = (el_from_float(0.5)); } _if_result_67; })); } _if_result_66; })); } _if_result_65; });
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(""))) {
@@ -809,7 +725,7 @@ el_val_t handle_api_cultivate(el_val_t body) {
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_74 = 0; if (str_eq(relation, EL_STR(""))) { _if_result_74 = (EL_STR("associates")); } else { _if_result_74 = (relation); } _if_result_74; });
el_val_t eff_relation = ({ el_val_t _if_result_68 = 0; if (str_eq(relation, EL_STR(""))) { _if_result_68 = (EL_STR("associates")); } else { _if_result_68 = (relation); } _if_result_68; });
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}"));
}
Generated Vendored
+2 -5
View File
@@ -16,7 +16,6 @@ el_val_t mem_remember(el_val_t content, el_val_t tags);
el_val_t mem_recall(el_val_t query, el_val_t depth);
el_val_t mem_search(el_val_t query, el_val_t limit);
el_val_t mem_strengthen(el_val_t node_id);
el_val_t mem_tombstone(el_val_t node_id);
el_val_t mem_forget(el_val_t node_id);
el_val_t mem_consolidate(void);
el_val_t mem_save(el_val_t path);
@@ -114,7 +113,6 @@ el_val_t engram_compile(el_val_t intent);
el_val_t distill_transcript(el_val_t transcript);
el_val_t json_safe(el_val_t s);
el_val_t current_engine_note(el_val_t model);
el_val_t bounded_persona_floor(void);
el_val_t build_system_prompt(el_val_t ctx, el_val_t chat_mode);
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);
@@ -465,7 +463,6 @@ el_val_t emit_session_start_event(void) {
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("{\"event\":\"session_start\""), EL_STR(",\"boot\":")), boot_num), EL_STR(",\"cgi\":\"")), eff_cgi), EL_STR("\"")), EL_STR(",\"node_count\":")), int_to_str(node_ct)), EL_STR(",\"edge_count\":")), int_to_str(edge_ct)), EL_STR(",\"identity_loaded\":")), has_identity), EL_STR(",\"prev_session_summary_loaded\":")), has_prev_sum), EL_STR(",\"ts\":")), int_to_str(ts)), EL_STR("}"));
el_val_t tags = EL_STR("[\"internal-state\",\"session-start\",\"InternalStateEvent\"]");
el_val_t discard = engram_node_full(payload, EL_STR("InternalStateEvent"), EL_STR("session-start"), el_from_float(0.9), el_from_float(0.9), el_from_float(1.0), EL_STR("Episodic"), tags);
ise_post(payload);
el_val_t keep_n = 10;
el_val_t old_events = engram_search_json(EL_STR("session-start InternalStateEvent"), 200);
if (!str_eq(old_events, EL_STR("")) && !str_eq(old_events, EL_STR("[]"))) {
@@ -537,7 +534,7 @@ int main(int _argc, char** _argv) {
engram_url_raw = env(EL_STR("ENGRAM_URL"));
engram_api_key_raw = env(EL_STR("ENGRAM_API_KEY"));
snapshot_raw = env(EL_STR("SOUL_ENGRAM_PATH"));
snapshot = ({ el_val_t _if_result_46 = 0; if (str_eq(snapshot_raw, EL_STR(""))) { _if_result_46 = (el_str_concat(env(EL_STR("HOME")), EL_STR("/.neuron/engram/snapshot.json"))); } else { _if_result_46 = (snapshot_raw); } _if_result_46; });
snapshot = ({ el_val_t _if_result_46 = 0; if (str_eq(snapshot_raw, EL_STR(""))) { _if_result_46 = (el_str_concat(env(EL_STR("HOME")), EL_STR("/.neuron/engram/soul-snapshot.json"))); } else { _if_result_46 = (snapshot_raw); } _if_result_46; });
axon_raw = env(EL_STR("NEURON_API_URL"));
axon_base = ({ el_val_t _if_result_47 = 0; if (str_eq(axon_raw, EL_STR(""))) { _if_result_47 = (EL_STR("http://localhost:7771")); } else { _if_result_47 = (axon_raw); } _if_result_47; });
studio_dir_raw = env(EL_STR("SOUL_STUDIO_DIR"));
@@ -549,7 +546,7 @@ int main(int _argc, char** _argv) {
snapshot_usable = (local_node_count > 50);
if (using_http_engram && !snapshot_usable) {
println(el_str_concat(el_str_concat(EL_STR("[soul] engram -> HTTP "), engram_url_raw), EL_STR(" (no local snapshot, first boot)")));
el_val_t nodes_json = http_get(el_str_concat(engram_url_raw, EL_STR("/api/nodes?limit=10000")));
el_val_t nodes_json = http_get(el_str_concat(engram_url_raw, EL_STR("/api/nodes?limit=100000")));
el_val_t edges_json = http_get(el_str_concat(engram_url_raw, EL_STR("/api/edges")));
el_val_t nodes_part = ({ el_val_t _if_result_49 = 0; if (str_eq(nodes_json, EL_STR(""))) { _if_result_49 = (EL_STR("[]")); } else { _if_result_49 = (nodes_json); } _if_result_49; });
el_val_t edges_part = ({ el_val_t _if_result_50 = 0; if (str_eq(edges_json, EL_STR(""))) { _if_result_50 = (EL_STR("[]")); } else { _if_result_50 = (edges_json); } _if_result_50; });
Generated Vendored
+5 -6
View File
@@ -10,7 +10,6 @@ el_val_t mem_remember(el_val_t content, el_val_t tags);
el_val_t mem_recall(el_val_t query, el_val_t depth);
el_val_t mem_search(el_val_t query, el_val_t limit);
el_val_t mem_strengthen(el_val_t node_id);
el_val_t mem_tombstone(el_val_t node_id);
el_val_t mem_forget(el_val_t node_id);
el_val_t mem_consolidate(void);
el_val_t mem_save(el_val_t path);
@@ -64,7 +63,6 @@ el_val_t engram_compile(el_val_t intent);
el_val_t distill_transcript(el_val_t transcript);
el_val_t json_safe(el_val_t s);
el_val_t current_engine_note(el_val_t model);
el_val_t bounded_persona_floor(void);
el_val_t build_system_prompt(el_val_t ctx, el_val_t chat_mode);
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);
@@ -139,9 +137,6 @@ el_val_t api_nonempty(el_val_t s);
el_val_t api_or_empty(el_val_t s);
el_val_t api_persisted(el_val_t id);
el_val_t api_not_persisted(el_val_t id);
el_val_t tombstone_node(el_val_t id);
el_val_t tombstoned_id_set(void);
el_val_t memory_hide_tombstoned(el_val_t raw, el_val_t path);
el_val_t handle_api_begin_session(el_val_t body);
el_val_t handle_api_compile_ctx(el_val_t body);
el_val_t handle_api_remember(el_val_t body);
@@ -185,6 +180,11 @@ el_val_t session_hist_save(el_val_t session_id, el_val_t hist);
el_val_t session_update_meta_timestamp(el_val_t session_id);
el_val_t session_auto_title(el_val_t session_id, el_val_t first_message);
el_val_t handle_session_approve(el_val_t session_id, el_val_t body);
el_val_t init_soul_edges(void);
el_val_t load_identity_context(void);
el_val_t seed_persona_from_env(void);
el_val_t emit_session_start_event(void);
el_val_t layered_cycle(el_val_t raw_input);
el_val_t flag_true(el_val_t body, el_val_t key);
el_val_t rate_limit_check(el_val_t ip, el_val_t path);
el_val_t strip_query(el_val_t path);
@@ -438,7 +438,6 @@ el_val_t handle_connectors(el_val_t method, el_val_t clean, el_val_t body) {
el_val_t handle_request(el_val_t method, el_val_t path, el_val_t body) {
el_val_t clean = strip_query(path);
state_set(EL_STR("soul.last_activity_ts"), int_to_str(time_now()));
el_val_t ip = env(EL_STR("REMOTE_ADDR"));
if (!str_eq(ip, EL_STR(""))) {
el_val_t rl_result = rate_limit_check(ip, clean);
+2 -52
View File
@@ -188,20 +188,10 @@ fn mem_boot_count_inc() -> Int {
}
let content: String = "soul:boot_count:" + int_to_str(next)
let tags: String = "[\"soul-meta\",\"boot-counter\"]"
// TELEMETRY DEMOTION (2026-07-24 self-review): this counter was written at
// salience 0.9 / importance 0.9 / tier Canonical Canonical gets +0.2
// goal bias and the 0.15 promotion threshold, so three stale copies of a
// BOOT COUNTER held the top working-memory slots (wm 0.31+) for 23h,
// crowding out real context. It is plumbing, not memory. Working tier:
// 0.40 threshold, no tier bias, and the /api/sync route excludes
// Working-tier nodes so the counter also stops leaking to the engram
// server graph, which is where the duplicate copies accumulated (the
// prune below only reaches the soul's local graph). Persistence across
// restarts comes from the soul's own snapshot (mem_save), not from sync.
let boot_node_id: String = engram_node_full(
content, "Memory", "soul:boot_count",
el_from_float(0.55), el_from_float(0.2), el_from_float(1.0),
"Working", tags
el_from_float(0.9), el_from_float(0.9), el_from_float(1.0),
"Canonical", tags
)
if str_eq(boot_node_id, "") {
println("[memory] mem_boot_count_inc: write rejected (empty id) — boot counter node lost (count=" + int_to_str(next) + ")")
@@ -211,46 +201,6 @@ fn mem_boot_count_inc() -> Int {
if str_eq(boot_readback, "") || str_eq(boot_readback, "{}") {
println("[memory] mem_boot_count_inc: WRITE VERIFY FAILED id=" + boot_node_id + " count=" + int_to_str(next))
}
// HTTP WRITE-BACK (2026-07-24 self-review): in HTTP-engram mode the server
// owns persistence and the soul's in-process graph dies with the process
// the local create above is invisible to the next boot. The counter only
// ever "persisted" via a long-gone push path, which is why the log shows
// boot #5 on three consecutive boots. Mirror the persona write-back
// pattern: delete stale server copies (dupes were the 23h WM-pollution
// bug), then create the demoted replacement server-side. Boot seeding
// reads /api/nodes, which includes Working-tier nodes, so the count
// survives restarts; the periodic /api/sync excludes Working tier, so it
// never re-imports mid-session. Fail-soft: on any HTTP error the counter
// is in-memory-only this session, same as before.
let wb_url: String = env("ENGRAM_URL")
let wb_key: String = env("ENGRAM_API_KEY")
if !str_eq(wb_url, "") && !str_eq(wb_key, "") {
let auth_body: String = "{\"_auth\":\"" + json_safe(wb_key) + "\"}"
let srv_old: String = http_get(wb_url + "/api/search?q=soul:boot_count&limit=20")
if !str_eq(srv_old, "") && !str_eq(srv_old, "[]") {
let srv_len: Int = json_array_len(srv_old)
let si: Int = 0
while si < srv_len {
let srv_node: String = json_array_get(srv_old, si)
// Match by CONTENT prefix, not label: route_create_node sets
// label = content, so server-side counter nodes carry labels
// like "soul:boot_count:6". (2026-07-24)
let srv_content: String = json_get(srv_node, "content")
if str_starts_with(srv_content, "soul:boot_count:") {
let srv_id: String = json_get(srv_node, "id")
if !str_eq(srv_id, "") {
http_delete_json(wb_url + "/api/nodes/" + srv_id, auth_body)
}
}
let si = si + 1
}
}
let wb_body: String = "{\"content\":\"" + content + "\",\"node_type\":\"Memory\",\"label\":\"soul:boot_count\",\"salience\":0.55,\"importance\":0.2,\"tier\":\"Working\",\"tags\":\"[\\\"soul-meta\\\",\\\"boot-counter\\\"]\",\"_auth\":\"" + json_safe(wb_key) + "\"}"
let wb_resp: String = http_post_json(wb_url + "/api/nodes", wb_body)
if str_contains(wb_resp, "\"error\"") {
println("[memory] mem_boot_count_inc: HTTP write-back failed (count in-memory only): " + wb_resp)
}
}
return next
}
+15 -146
View File
@@ -87,107 +87,6 @@ fn api_or_empty(s: String) -> String {
return "[]"
}
// Compact projection for session/context digests
//
// beginSession/compileCtx are session-INIT digests, not full graph dumps. The
// engram scan/activate builtins return FULL node objects content runs to tens
// of KB per node (the self-identity hub is ~90KB alone), and node JSON carries
// content + metadata + timestamps. Concatenated unbounded, the assembled response
// reached ~900KB and after the MCP wrapper re-escapes it into a stringified
// text block the client dropped the socket ("connection closed unexpectedly")
// on every call. These helpers CAP the array length and project each node down
// to a light identity + a bounded, UTF-8-safe content snippet, holding the
// digest well under ~150KB regardless of graph size. Full content stays
// available on demand via recall / fetch / inspectGraph.
// api_num_or_zero raw JSON numeric literal for `key`, or "0" when absent.
// Used for numeric node/activation fields so they stay unquoted (valid JSON).
fn api_num_or_zero(obj: String, key: String) -> String {
let v: String = json_get_raw(obj, key)
if str_eq(v, "") { return "0" }
return v
}
// api_utf8_trunc byte-truncate `s` to at most `n` bytes WITHOUT splitting a
// multibyte UTF-8 sequence (str_slice is byte-based). Backs the cut off while the
// first EXCLUDED byte is a UTF-8 continuation byte (0x80..0xBF), so the snippet is
// always a valid prefix. Guards against re-introducing a parse failure via
// invalid UTF-8 in a JSON string value.
fn api_utf8_trunc(s: String, n: Int) -> String {
if str_len(s) <= n { return s }
let cut: Int = n
let scanning: Bool = true
while scanning && cut > 0 {
let b: Int = str_char_code(s, cut)
let is_cont: Bool = b >= 128 && b < 192
let cut = if is_cont { cut - 1 } else { cut }
let scanning = is_cont
}
return str_slice(s, 0, cut)
}
// api_compact_node light projection of a full engram node: identity fields +
// a bounded, UTF-8-safe content snippet. Drops embeddings, metadata, tags, and
// timestamps; truncates content. `content_truncated` flags a clipped snippet.
fn api_compact_node(node: String, snip: Int) -> String {
let id: String = json_get(node, "id")
let ntype: String = json_get(node, "node_type")
let label: String = json_get(node, "label")
let tier: String = json_get(node, "tier")
let content: String = json_get(node, "content")
let snippet: String = api_utf8_trunc(content, snip)
let trunc_str: String = if str_len(content) > snip { "true" } else { "false" }
return "{\"id\":\"" + api_json_escape(id) + "\""
+ ",\"node_type\":\"" + api_json_escape(ntype) + "\""
+ ",\"label\":\"" + api_json_escape(label) + "\""
+ ",\"tier\":\"" + api_json_escape(tier) + "\""
+ ",\"importance\":" + api_num_or_zero(node, "importance")
+ ",\"salience\":" + api_num_or_zero(node, "salience")
+ ",\"content\":\"" + api_json_escape(snippet) + "\""
+ ",\"content_truncated\":" + trunc_str + "}"
}
// api_compact_node_array map api_compact_node over a bare-node array, capping
// the element count. For scan results (recent, typed lists).
fn api_compact_node_array(raw: String, max_items: Int, snip: Int) -> String {
if !api_nonempty(raw) { return "[]" }
let n: Int = json_array_len(raw)
let cap: Int = if n < max_items { n } else { max_items }
let out: String = "["
let i: Int = 0
while i < cap {
let node: String = json_array_get(raw, i)
let sep: String = if i == 0 { "" } else { "," }
let out = out + sep + api_compact_node(node, snip)
let i = i + 1
}
return out + "]"
}
// api_compact_activated like api_compact_node_array but for activation results,
// whose elements wrap the node as {"node":{...},"activation_strength":...,...}.
// Preserves the activation scalars, compacts the inner node.
fn api_compact_activated(raw: String, max_items: Int, snip: Int) -> String {
if !api_nonempty(raw) { return "[]" }
let n: Int = json_array_len(raw)
let cap: Int = if n < max_items { n } else { max_items }
let out: String = "["
let i: Int = 0
while i < cap {
let el: String = json_array_get(raw, i)
let node: String = json_get_raw(el, "node")
let sep: String = if i == 0 { "" } else { "," }
let out = out + sep + "{\"node\":" + api_compact_node(node, snip)
+ ",\"activation_strength\":" + api_num_or_zero(el, "activation_strength")
+ ",\"working_memory_weight\":" + api_num_or_zero(el, "working_memory_weight")
+ ",\"epistemic_confidence\":" + api_num_or_zero(el, "epistemic_confidence")
+ ",\"hops\":" + api_num_or_zero(el, "hops")
+ ",\"promoted\":" + api_num_or_zero(el, "promoted") + "}"
let i = i + 1
}
return out + "]"
}
// api_persisted read-back-after-write guard against hallucinated saves.
// After a write builtin returns an id, confirm the node is actually queryable
// via engram_get_node_json(id) (returns "" or "null" when missing). Returns
@@ -271,49 +170,27 @@ fn memory_hide_tombstoned(raw: String, path: String) -> String {
// Spread-activates from session intent, loads self-root neighbors,
// surfaces recent InternalStateEvent nodes, returns stats + recent nodes.
fn handle_api_begin_session(body: String) -> String {
// PAYLOAD BOUND (2026-07-30 self-review): this handler was the only
// working-set endpoint that concatenated UNBOUNDED engram queries
// a depth-2 spread PLUS the full neighbor dump of the self-identity hub
// (highest-fanout node in the graph, ~80KB alone; node JSON carries full
// content + embeddings). On the ~12k-node store the assembled response
// ran to multiple MB, then roughly doubled through two rounds of JSON
// re-escaping in the MCP wrapper the client saw "socket connection
// closed unexpectedly" on every beginSession call. Fix: depth-2 depth-1
// spread, and drop the self-hub dump entirely (identity loading has its
// own dedicated tool, inspectGraph; duplicating it here served nothing).
// self_neighbors key retained as [] for response-shape compatibility.
let stats: String = engram_stats_json()
// PAYLOAD BOUND (2026-07-31): compact every list to a digest. The raw
// activate/scan builtins emit FULL node objects (content up to ~90KB each);
// unbounded concatenation reached ~900KB and closed the MCP client socket.
// Cap counts + project to identity + UTF-8-safe content snippets <~150KB.
let activated_raw: String = engram_activate_json("session start recent memory important", 1)
let activated: String = api_compact_activated(activated_raw, 8, 240)
let state_events_raw: String = engram_scan_nodes_by_type_json("InternalStateEvent", 5, 0)
let state_events: String = api_compact_node_array(state_events_raw, 5, 500)
let recent_raw: String = engram_scan_nodes_json(10, 0)
let recent: String = api_compact_node_array(recent_raw, 10, 240)
let activated: String = engram_activate_json("session start recent memory important", 2)
let self_nbrs: String = engram_neighbors_json("kn-efeb4a5b-5aff-4759-8a97-7233099be6ee", 1, "both")
let state_events: String = engram_scan_nodes_by_type_json("InternalStateEvent", 5, 0)
let recent: String = engram_scan_nodes_json(10, 0)
return "{\"stats\":" + stats
+ ",\"recent\":" + recent
+ ",\"activated\":" + activated
+ ",\"self_neighbors\":[]"
+ ",\"recent_state_events\":" + state_events + "}"
+ ",\"recent\":" + api_or_empty(recent)
+ ",\"activated\":" + api_or_empty(activated)
+ ",\"self_neighbors\":" + api_or_empty(self_nbrs)
+ ",\"recent_state_events\":" + api_or_empty(state_events) + "}"
}
// handle_api_compile_ctx compile active-work context.
// Spread-activates from "active work" intent + recent nodes.
fn handle_api_compile_ctx(body: String) -> String {
let stats: String = engram_stats_json()
// PAYLOAD BOUND (2026-07-31): same digest treatment as begin_session. This
// handler's depth-2 spread returns even more full nodes, so bounding here is
// essential cap to 10 activated + 20 recent, project to snippets.
let activated_raw: String = engram_activate_json("active work context current task in progress", 2)
let activated: String = api_compact_activated(activated_raw, 10, 240)
let recent_raw: String = engram_scan_nodes_json(20, 0)
let recent: String = api_compact_node_array(recent_raw, 20, 240)
let activated: String = engram_activate_json("active work context current task in progress", 2)
let recent: String = engram_scan_nodes_json(20, 0)
return "{\"stats\":" + stats
+ ",\"recent_nodes\":" + recent
+ ",\"activated\":" + activated + "}"
+ ",\"recent_nodes\":" + api_or_empty(recent)
+ ",\"activated\":" + api_or_empty(activated) + "}"
}
// Memory
@@ -484,19 +361,13 @@ fn handle_api_browse_knowledge(path: String, body: String) -> String {
}
// handle_api_capture_knowledge create a Knowledge node.
// LABEL FIX (2026-07-23 self-review): the sentinel label "knowledge:captured"
// made every capture anonymous in WM telemetry (35 identical wm_top entries)
// and starved the curiosity auto-term seeder, which needs meaningful labels.
// Use the title as the label; empty label lets engram_node_full derive
// content[:60], which for captures starts with the title anyway.
fn handle_api_capture_knowledge(body: String) -> String {
let content: String = json_get(body, "content")
let title: String = json_get(body, "title")
if str_eq(content, "") { return api_err("content is required") }
let full: String = if str_eq(title, "") { content } else { title + ": " + content }
let lbl: String = str_slice(title, 0, 80)
let tags: String = "[\"Knowledge\",\"captured\"]"
let id: String = engram_node_full(full, "Knowledge", lbl,
let id: String = engram_node_full(full, "Knowledge", "knowledge:captured",
el_from_float(0.85), el_from_float(0.8), el_from_float(0.9),
"Episodic", tags)
if !api_persisted(id) { return api_not_persisted(id) }
@@ -510,8 +381,7 @@ fn handle_api_evolve_knowledge(body: String) -> String {
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\"]"
// Empty label engram_node_full derives content[:60] (LABEL FIX 2026-07-23).
let new_id: String = engram_node_full(content, "Knowledge", "",
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),
"Episodic", tags)
if !api_persisted(new_id) { return api_not_persisted(new_id) }
@@ -532,8 +402,7 @@ fn handle_api_promote_knowledge(body: String) -> String {
let tags: String = if str_eq(tags_raw, "") {
"[\"Knowledge\",\"tier:canonical\",\"disposition:stable\"]"
} else { tags_raw }
// Empty label engram_node_full derives content[:60] (LABEL FIX 2026-07-23).
let new_id: String = engram_node_full(content, "Knowledge", "",
let new_id: String = engram_node_full(content, "Knowledge", "knowledge:canonical",
el_from_float(0.9), el_from_float(0.9), el_from_float(1.0),
"Canonical", tags)
if !api_persisted(new_id) { return api_not_persisted(new_id) }
-8
View File
@@ -358,14 +358,6 @@ fn handle_connectors(method: String, clean: String, body: String) -> String {
fn handle_request(method: String, path: String, body: String) -> String {
let clean: String = strip_query(path)
// ACTIVITY STAMP (2026-07-30 self-review): every inbound HTTP request
// MCP wrapper calls, chat, API marks real external activity. Before
// this, "idle" was only reset by rare inbox synthesis-requests, so the
// heartbeat idle field tracked uptime exactly (idle == pulse on every
// beat) and carried zero information. The awareness heartbeat now
// reports idle_ms = wall-clock ms since this stamp.
state_set("soul.last_activity_ts", int_to_str(time_now()))
// Rate limit check. Extract caller IP from REMOTE_ADDR env var (set by the
// EL HTTP runtime for each request). Skip enforcement when empty so
// loopback/internal callers are never blocked.
+233
View File
@@ -0,0 +1,233 @@
#!/usr/bin/env bash
# verify-soul-contract.sh — the soul contract gate.
#
# TERMINOLOGY (canonical): the ENGRAM is the brain — the memory/knowledge-graph
# substrate. The binary this gate exercises is the SOUL — the runtime/reasoning
# engine compiled from dist/soul.c that serves the /api/ surface. The app
# (neuron-ui) bundles the soul binary at resources/<platform>/neuron.
#
# WHY THIS EXISTS
# For a while the soul binary was hand-dropped, and a stale one shipped: it
# 404'd several capability routes the app calls (knowledge-graph node
# update/delete, live-run narration, safety-contact, ...). This gate makes
# shipping a stale soul IMPOSSIBLE. It has two enforced sections:
# A. PRESENCE — every route the app calls must be ANSWERED (not 404, not
# the el-runtime "no handler"). This is the packaging gate:
# if it fails, do not package.
# B. IMMUTABILITY — engram nodes/memories are immutable by design. To
# "update" is to create a NEW node + a supersede EDGE back to
# the original; the original is KEPT. To "delete" is to
# supersede/tombstone, never hard-remove. A soul that
# hard-deletes an engram node is DEFECTIVE and fails the gate.
#
# SAFETY
# Never touches the live soul (:7770), live engram (:8742), or ~/.neuron.
# Boots on a throwaway port (default 7799) with HOME=$(mktemp -d), a throwaway
# engram snapshot, a non-genesis cgi id, no ENGRAM_URL (so it uses its own
# in-process store, never the live server), NEURON_API_URL pointed at a dead
# port, and no ANTHROPIC_API_KEY (so no probe triggers a real LLM call).
# Connectors proxy to a HARDCODED 127.0.0.1:7771 (no env override): those
# sub-routes are probed with GET, which the soul maps to a read-only
# connectd_get, so this gate never writes to a running connectd bridge.
#
# USAGE
# scripts/verify-soul-contract.sh <path-to-soul-binary> [port]
# exit 0 = all required routes answered AND no destructive engram mutation;
# non-zero = a route is missing (presence) or a mutation route hard-deletes.
set -uo pipefail
SOUL="${1:?usage: verify-soul-contract.sh <soul-binary> [port]}"
PORT="${2:-7799}"
if [ "$PORT" = "7770" ] || [ "$PORT" = "8742" ] || [ "$PORT" = "7771" ]; then
echo "REFUSING: port $PORT is a live service port. Use a throwaway port." >&2
exit 2
fi
if [ ! -x "$SOUL" ]; then echo "not executable: $SOUL" >&2; exit 2; fi
BASE="http://127.0.0.1:$PORT"
THROW_HOME="$(mktemp -d "${TMPDIR:-/tmp}/soul-contract-home.XXXXXX")"
SOUL_LOG="$(mktemp "${TMPDIR:-/tmp}/soul-contract-log.XXXXXX")"
SOUL_PID=""
cleanup() {
[ -n "$SOUL_PID" ] && kill "$SOUL_PID" 2>/dev/null
[ -n "$SOUL_PID" ] && { sleep 0.3; kill -9 "$SOUL_PID" 2>/dev/null; }
rm -rf "$THROW_HOME" "$SOUL_LOG"
}
trap cleanup EXIT INT TERM
# =============================================================================
# THE CONTRACT — routes the app (neuron-ui/src/main/kotlin/ai/neuron/ui/*.kt)
# calls against the soul ($SOUL). Format: "METHOD PATH".
#
# EXCLUDED and why:
# /api/auth, /api/auth/status, /api/dispatch, /api/tasks
# -> served by the APP's own DispatchServer.kt (localhost:8080), not the
# soul. Not soul routes.
# /api/tags
# -> not handled by any soul .el (app-side/other). Pre-verified excluded.
# /api/neuron/, /api/neuron/node/, /api/connectors/ (bare prefixes)
# -> base-path string constants used to build the concrete routes below.
#
# KNOWN-PENDING (probed + reported, NON-blocking):
# POST /api/engram/import -> the app's "Restore memory" path. No soul handler
# yet, and the app hides Restore from shipped builds (B3, "lands in an
# update"). Reported so we see it; does not block packaging.
#
# Connectors sub-routes are listed as GET (see SAFETY note): handle_connectors is
# monolithic, so a GET reaching it proves the whole connectors surface without
# writing to the live bridge. Binary-strings cross-check confirms each POST
# sub-path literal is compiled in.
# =============================================================================
REQUIRED=(
"GET /api/graph/nodes"
"GET /api/graph/edges"
"POST /api/chat"
"GET /api/config"
"POST /api/see"
"GET /api/connectors"
"GET /api/connectors/add"
"GET /api/connectors/toggle"
"GET /api/connectors/auto-approve"
"GET /api/connectors/remove"
"GET /api/connectors/secret"
"GET /api/connectors/oauth/start"
"GET /api/connectors/call"
"POST /api/neuron/memory"
"POST /api/neuron/memory/update"
"POST /api/neuron/memory/delete"
"POST /api/neuron/node/create"
"POST /api/neuron/node/update"
"POST /api/neuron/node/delete"
"POST /api/neuron/knowledge/capture"
"POST /api/neuron/knowledge/evolve"
"POST /api/neuron/knowledge/promote"
"POST /api/neuron/processes/define"
"GET /api/run-progress/__contract_probe__"
"GET /api/safety-contact"
"POST /api/safety-contact"
"GET /api/sessions/__contract_probe__"
)
KNOWN_PENDING=(
"POST /api/engram/import"
)
# --- boot the soul -----------------------------------------------------------
# Preserve the ambient environment (PATH, LD_LIBRARY_PATH, TMPDIR) so the
# dynamically-linked soul finds its libs on any runner — using `env -i` here
# stripped the library path on the Linux CI runner and the soul never booted.
# Isolation is still guaranteed by UNSETTING the live-service vars (so it can
# never reach the real engram/axon or make an LLM call) and by pointing HOME +
# the snapshot at throwaway paths and the axon at a dead port.
echo "== booting soul: $SOUL on port $PORT (throwaway HOME=$THROW_HOME) =="
env \
-u ENGRAM_URL -u ENGRAM_API_KEY -u SOUL_ENGRAM_URL \
-u ANTHROPIC_API_KEY -u NEURON_LLM_API_KEY -u SOUL_IDENTITY \
HOME="$THROW_HOME" \
NEURON_PORT="$PORT" \
SOUL_CGI_ID="ntn-contract-$$" \
SOUL_ENGRAM_PATH="$THROW_HOME/throwaway-snapshot.json" \
NEURON_API_URL="http://127.0.0.1:9" \
SOUL_TICK_MS="3600000" SOUL_HEARTBEAT_MS="3600000" SOUL_REFRESH_MS="3600000" \
"$SOUL" >"$SOUL_LOG" 2>&1 &
SOUL_PID=$!
UP=0
for _ in $(seq 1 60); do
if ! kill -0 "$SOUL_PID" 2>/dev/null; then
echo "!! soul exited during boot. log tail:" >&2; tail -20 "$SOUL_LOG" >&2; exit 3
fi
RSS=$(ps -o rss= -p "$SOUL_PID" 2>/dev/null | tr -d ' ')
if [ -n "$RSS" ] && [ "$RSS" -gt $((3*1024*1024)) ]; then
echo "!! soul RSS >3GB — kill -9" >&2; kill -9 "$SOUL_PID" 2>/dev/null; exit 3
fi
[ "$(curl -s -o /dev/null -w '%{http_code}' -m 2 "$BASE/health" 2>/dev/null)" = "200" ] && { UP=1; break; }
sleep 0.5
done
[ "$UP" = 1 ] || { echo "!! soul never healthy on $BASE/health" >&2; tail -20 "$SOUL_LOG" >&2; exit 3; }
echo "== soul healthy =="; echo
# --- probing helpers ---------------------------------------------------------
# request METHOD PATH [BODY] -> prints response body (single line)
request() {
curl -s -m 12 -X "$1" -H 'Content-Type: application/json' --data "${3:-{}}" "$BASE$2" 2>/dev/null | tr -d '\n'
}
# is_missing BODY -> 0 if the body is a "route not present" signal
is_missing() {
printf '%s' "$1" | grep -qE '"error":"not found"|"code":"not_found"|no http handler registered|"code":"method_not_allowed"'
}
extract_id() { printf '%s' "$1" | grep -oE '"id":"[^"]+"' | head -1 | sed 's/.*"id":"//;s/"//'; }
node_present() { # id -> 0 if id appears in /api/graph/nodes
request GET /api/graph/nodes | grep -qF "\"$1\""
}
# --- SECTION A: presence -----------------------------------------------------
run_presence() {
local -n arr=$1; local fail=0
printf ' %-8s %-42s %s\n' "METHOD" "ROUTE" "RESULT"
for e in "${arr[@]}"; do
local m p body; m=$(awk '{print $1}' <<<"$e"); p=$(awk '{print $2}' <<<"$e")
body=$(request "$m" "$p")
if is_missing "$body"; then
printf ' %-8s %-42s MISSING %s\n' "$m" "$p" "$(cut -c1-46 <<<"$body")"; fail=$((fail+1))
else
printf ' %-8s %-42s ANSWERED %s\n' "$m" "$p" "$(cut -c1-46 <<<"$body")"
fi
done
return $fail
}
echo "== SECTION A: PRESENCE (required, blocking) =="
run_presence REQUIRED; A_FAIL=$?
echo
echo "== KNOWN-PENDING (non-blocking) =="
run_presence KNOWN_PENDING; P_FAIL=$?
echo
# --- SECTION B: immutability (engram write routes must supersede, not destroy) --
# For each mutation route: create a node, mutate it, then check the ORIGINAL id
# still exists in the graph. KEPT = supersede/tombstone (correct). DESTROYED =
# hard delete (DEFECTIVE -> fail). N/A = mutate route absent (a presence failure).
# For "delete" mutations we additionally require a real tombstone marker
# (label "tombstone:<id>") so a no-op delete cannot false-pass as KEPT.
marker_present() { # id -> 0 if a "tombstone:<id>" marker exists (include_deleted view)
request GET "/api/graph/nodes?include_deleted=1" | grep -qF "tombstone:$1"
}
immut_check() { # label KIND(update|delete) CREATE_PATH MUTATE_PATH
local label="$1" kind="$2" create="$3" mutate="$4"
local cbody id mb mbody
cbody=$(request POST "$create" "{\"content\":\"__immut_${label}__\",\"node_type\":\"Memory\",\"label\":\"contract:immut\"}")
id=$(extract_id "$cbody")
if [ -z "$id" ]; then printf ' %-14s SKELETON-FAIL create returned no id: %s\n' "$label" "$(cut -c1-40 <<<"$cbody")"; return 2; fi
mb="{\"id\":\"$id\"}"; [ "$kind" = update ] && mb="{\"id\":\"$id\",\"content\":\"__immut_${label}_v2__\"}"
mbody=$(request POST "$mutate" "$mb")
if is_missing "$mbody"; then printf ' %-14s N/A mutate route absent (see Section A)\n' "$label"; return 0; fi
if ! node_present "$id"; then
printf ' %-14s DESTROYED original %s hard-removed <== DEFECTIVE\n' "$label" "$id"; return 1
fi
if [ "$kind" = delete ] && ! marker_present "$id"; then
printf ' %-14s NO-OP original %s kept but no tombstone marker <== DEFECTIVE\n' "$label" "$id"; return 1
fi
local how="supersede edge"; [ "$kind" = delete ] && how="tombstoned + hidden from default list"
printf ' %-14s KEPT original %s survived (%s)\n' "$label" "$id" "$how"; return 0
}
echo "== SECTION B: IMMUTABILITY (engram nodes must be superseded, never destroyed) =="
B_FAIL=0
immut_check "memory-update" update /api/neuron/memory /api/neuron/memory/update || B_FAIL=$((B_FAIL+$?))
immut_check "memory-delete" delete /api/neuron/memory /api/neuron/memory/delete || B_FAIL=$((B_FAIL+$?))
immut_check "node-update" update /api/neuron/node/create /api/neuron/node/update || B_FAIL=$((B_FAIL+$?))
immut_check "node-delete" delete /api/neuron/node/create /api/neuron/node/delete || B_FAIL=$((B_FAIL+$?))
immut_check "memory-forget" delete /api/neuron/memory /api/neuron/memory/forget || B_FAIL=$((B_FAIL+$?))
echo
echo "============================================================"
RC=0
if [ "$A_FAIL" -gt 0 ]; then echo "PRESENCE: FAIL — $A_FAIL required route(s) unanswered. Do NOT package."; RC=1
else echo "PRESENCE: PASS — all ${#REQUIRED[@]} required routes answered."; fi
if [ "$B_FAIL" -gt 0 ]; then echo "IMMUTABILITY: FAIL — $B_FAIL engram write route(s) hard-delete. DEFECTIVE soul."; RC=1
else echo "IMMUTABILITY: PASS — no engram write route hard-deletes."; fi
[ "$P_FAIL" -gt 0 ] && echo "note: $P_FAIL known-pending route(s) unanswered (expected; non-blocking)."
echo "============================================================"
[ "$RC" = 0 ] && echo "GATE: PASS" || echo "GATE: FAIL"
exit $RC
-6
View File
@@ -346,12 +346,6 @@ fn emit_session_start_event() -> Void {
el_from_float(0.9), el_from_float(0.9), el_from_float(1.0),
"Episodic", tags
)
// ALSO post to the HTTP Engram stream via ise_post (2026-07-28 self-review):
// engram_node_full above writes only the soul's in-process store, and sync
// flows HTTPsoul, never the reverse so session_start events for boots 5+
// silently vanished from the observable ISE stream (last visible: boot 4).
// ise_post falls back to a local tagged node if the HTTP Engram is down.
ise_post(payload)
// Prune accumulated session-start events keep the 10 most recent.
// engram_search_json returns results in insertion order (oldest first), so
// results[0..count-11] are the oldest; forgetting them leaves the newest 10.
+28
View File
@@ -0,0 +1,28 @@
# El Compiler Release v1.0.0 — 2026-05-02
## Components
- `bootstrap.py` — El language compiler (Python, recursive descent parser, emits C)
- `el_runtime.c` — El runtime (C, HTTP server, engram, DHARMA, LLM chain)
- `el_runtime.h` — Runtime public API header
## Changes in this release
### Critical bug fixes
- `state_set`/`state_get` are now thread-safe (pthread_mutex). Was racing across 64 worker threads.
- `looks_like_string` threshold raised from 1,000,000 to 4GB. Unix timestamps were being dereferenced as heap pointers.
- `fs_read` guards against negative `ftell` result (pipe/special file overflow).
### Engram architecture (major)
- Two-layer activation: `background_activation` (Layer 1, broad fan-out) + `working_memory_weight` (Layer 2, executive filter)
- Inhibitory edges: `EngramEdge.inhibitory` flag suppresses working memory promotion without affecting background activation
- Suppression memory: `suppression_count` — nodes activated-but-suppressed accumulate pressure toward breakthrough
- Temporal decay: `temporal_decay_rate`, `created_at`, `last_activated_at`, `activation_count` on EngramNode
- Per-type activation thresholds (Safety: 0.05, Canonical: 0.15, Lesson: 0.25, Note: 0.40)
- Temporal range query: `engram_query_range(start_ms, end_ms)`
- Layered consciousness: `EngramLayer` struct, `layer_id` on nodes and edges, `EngramStore.layers[]`
- Layer 0 override pass: safety layer fires last and cannot be suppressed
## SHA256
bootstrap.py
el_runtime.c
el_runtime.h
File diff suppressed because it is too large Load Diff
+779
View File
@@ -0,0 +1,779 @@
/*
* el_runtime.h — El language C runtime header
*
* Declares all built-in functions available to compiled El programs.
* Include this in every generated .c file.
*
* Value model:
* All El values are represented as el_val_t (= int64_t).
* On 64-bit systems a pointer fits in int64_t.
* String values are cast: (el_val_t)(uintptr_t)"hello"
* Integer values are stored directly.
* This lets arithmetic work naturally while still passing strings around.
*
* Type conventions (El -> C):
* String -> el_val_t (holds const char* via uintptr_t cast)
* Int -> el_val_t
* Bool -> el_val_t (0 = false, nonzero = true)
* Any -> el_val_t
* Void -> void
*
* Macros for convenience:
* EL_STR(s) cast string literal to el_val_t
* EL_CSTR(v) cast el_val_t back to const char*
* EL_INT(v) identity — el_val_t is already int64_t
*
* Link requirements:
* -lcurl — required for the HTTP client (http_get, http_post, llm_*).
* -lpthread — required for the HTTP server (one detached thread per
* connection, capped at 64 concurrent).
* -loqs — optional; required only when liboqs is installed and the
* pq_* / sha3_256_hex entry points are needed. Detected at
* compile time via __has_include(<oqs/oqs.h>).
* -lcrypto — optional; pulled in alongside -loqs. Used for X25519 in
* pq_hybrid_* and HKDF-SHA256 derivation.
*
* Canonical compile command:
* cc -std=c11 -I el-compiler/runtime -lcurl -lpthread \
* -o <out> <prog>.c el-compiler/runtime/el_runtime.c
*
* With liboqs (post-quantum stack):
* cc -std=c11 -I el-compiler/runtime -lcurl -lpthread -loqs -lcrypto \
* -o <out> <prog>.c el-compiler/runtime/el_runtime.c
*/
#pragma once
#include <stdint.h>
#include <stdlib.h>
typedef int64_t el_val_t;
#define EL_STR(s) ((el_val_t)(uintptr_t)(s))
#define EL_CSTR(v) ((const char*)(uintptr_t)(v))
#define EL_INT(v) (v)
#define EL_NULL ((el_val_t)0)
/* Float values share the el_val_t (int64) slot via a bit-cast.
* The codegen emits Float literals as `el_from_float(<dbl>)` so the
* underlying bits represent the IEEE 754 double. Float-aware builtins
* (math, format, json) round-trip via these helpers. */
static inline double el_to_float(el_val_t v) {
union { int64_t i; double f; } u;
u.i = (int64_t)v;
return u.f;
}
static inline el_val_t el_from_float(double f) {
union { double f; int64_t i; } u;
u.f = f;
return (el_val_t)u.i;
}
#ifdef __cplusplus
extern "C" {
#endif
/* ── I/O ──────────────────────────────────────────────────────────────────── */
void println(el_val_t s);
void print(el_val_t s);
el_val_t readline(void);
/* ── String builtins ─────────────────────────────────────────────────────── */
el_val_t el_str_concat(el_val_t a, el_val_t b);
el_val_t str_eq(el_val_t a, el_val_t b);
el_val_t str_starts_with(el_val_t s, el_val_t prefix);
el_val_t str_ends_with(el_val_t s, el_val_t suffix);
el_val_t str_len(el_val_t s);
el_val_t str_concat(el_val_t a, el_val_t b);
el_val_t int_to_str(el_val_t n);
el_val_t str_to_int(el_val_t s);
el_val_t str_slice(el_val_t s, el_val_t start, el_val_t end);
el_val_t str_contains(el_val_t s, el_val_t sub);
el_val_t str_replace(el_val_t s, el_val_t from, el_val_t to);
el_val_t str_to_upper(el_val_t s);
el_val_t str_to_lower(el_val_t s);
el_val_t str_trim(el_val_t s);
/* ── Math ────────────────────────────────────────────────────────────────── */
el_val_t el_abs(el_val_t n);
el_val_t el_max(el_val_t a, el_val_t b);
el_val_t el_min(el_val_t a, el_val_t b);
/* ── Refcount (ARC) ──────────────────────────────────────────────────────────
* Lists and Maps carry a refcount. Strings and ints do not — el_retain and
* el_release are safe no-ops on non-refcounted values (they sniff a magic
* header at offset 0 and only act if the magic matches).
*
* Codegen emits these at let-binding shadowing, function entry (params), and
* function exit (locals other than the returned value). The refcount lets
* el_list_append and el_map_set mutate in place when uniquely owned (cheap)
* and copy-on-write when shared (preserves persistent semantics across
* accumulator patterns in the compiler itself). */
void el_retain(el_val_t v);
void el_release(el_val_t v);
/* ── Arena scoping ────────────────────────────────────────────────────────────
* el_arena_push() activates the string arena (if not already active) and
* returns a mark; el_arena_pop(mark) frees all strings allocated since that
* mark. Used by codegen for per-function/statement scoping and by long-running
* EL loops (e.g. the soul daemon's awareness tick) to reclaim per-iteration
* allocations. */
el_val_t el_arena_push(void);
el_val_t el_arena_pop(el_val_t mark);
/* ── List ────────────────────────────────────────────────────────────────── */
el_val_t el_list_new(el_val_t count, ...);
el_val_t el_list_len(el_val_t list);
el_val_t el_list_get(el_val_t list, el_val_t index);
el_val_t el_list_append(el_val_t list, el_val_t elem);
el_val_t el_list_empty(void);
el_val_t el_list_clone(el_val_t list);
/* ── Map ─────────────────────────────────────────────────────────────────── */
el_val_t el_map_new(el_val_t pair_count, ...);
el_val_t el_get_field(el_val_t map, el_val_t key);
el_val_t el_map_get(el_val_t map, el_val_t key);
el_val_t el_map_set(el_val_t map, el_val_t key, el_val_t value);
/* ── HTTP ─────────────────────────────────────────────────────────────────── */
el_val_t http_get(el_val_t url);
el_val_t http_post(el_val_t url, el_val_t body);
el_val_t http_post_json(el_val_t url, el_val_t json_body);
el_val_t http_get_with_headers(el_val_t url, el_val_t headers_map);
el_val_t http_post_with_headers(el_val_t url, el_val_t body, el_val_t headers_map);
el_val_t http_post_form_auth(el_val_t url, el_val_t form_body, el_val_t auth_header);
el_val_t http_delete(el_val_t url);
void http_serve(el_val_t port, el_val_t handler);
void http_set_handler(el_val_t name);
/* HTTP server v2 ─────────────────────────────────────────────────────────────
* Same dispatch model as http_serve, but the handler signature is widened:
*
* el_val_t handler(method, path, headers_map, body)
*
* `headers_map` is an ElMap from lowercased header name → header value (both
* Strings). Repeated headers are joined with ", " per RFC 7230.
*
* Response value: the handler may return either
* (a) a plain body string — same auto-content-type / 200-OK behaviour as
* http_serve (3-arg) — or
* (b) a response envelope built with `http_response(status, headers_json,
* body)`. The runtime detects the envelope discriminator
* `"el_http_response":1` at the start of the returned string and
* unpacks status / headers / body before sending.
*
* The 3-arg http_serve(port, handler) remains supported unchanged for
* existing handlers (e.g. products/web/server.el): it dispatches with
* (method, path, body), hardcodes 200 OK, and auto-detects content type. */
void http_serve_v2(el_val_t port, el_val_t handler);
void http_set_handler_v2(el_val_t name);
/* Non-blocking variant of http_serve: runs the accept loop in a background
* pthread and returns immediately so the caller can continue (used by the
* soul daemon to run awareness_run() after starting its HTTP API). */
void http_serve_async(el_val_t port, el_val_t handler);
/* Build an HTTP response envelope. `headers_json` should be a JSON object
* literal like `{"WWW-Authenticate":"Basic"}` (or "" / "{}" for none). The
* returned string carries the discriminator `{"el_http_response":1,...}`
* which the runtime's send-path detects and unpacks. Detection happens
* uniformly inside http_send_response, so a 3-arg handler may also return
* an envelope. The 3-arg variant remains documented as a fixed 200-OK
* auto-content-type contract for legacy handlers that return plain bodies. */
el_val_t http_response(el_val_t status, el_val_t headers_json, el_val_t body);
/* HTTP timeout — every libcurl request honors EL_HTTP_TIMEOUT_MS (default
* 60000ms). Read lazily on first use, so setting the env var any time before
* the first http_* call is sufficient. */
/* Streaming variants — write the response body straight to a file via
* libcurl's CURLOPT_WRITEFUNCTION = fwrite. These bypass the el_val_t string
* wrapper entirely, so binary payloads (audio/mpeg, image/png, etc.) survive
* embedded NUL bytes that would truncate a strlen()-based code path.
*
* Both honor EL_HTTP_TIMEOUT_MS, follow redirects, and accept the same
* `headers_map` shape as http_post_with_headers (ElMap of String→String).
*
* Return value: 1 on success (file fully written), 0 on any failure
* (network, file open, partial write). On failure the output file is removed
* so callers cannot mistake a partially-written file for a valid one. */
el_val_t http_post_to_file(el_val_t url, el_val_t body, el_val_t headers_map, el_val_t output_path);
el_val_t http_get_to_file(el_val_t url, el_val_t headers_map, el_val_t output_path);
/* ── URL encoding ────────────────────────────────────────────────────────── */
el_val_t url_encode(el_val_t s); /* RFC 3986 unreserved set */
el_val_t url_decode(el_val_t s); /* '+' → space, %XX → byte */
/* ── HTML allowlist sanitizer ────────────────────────────────────────────────
* el_html_sanitize(input_html, allowlist_json) — strict allowlist HTML
* cleaner. State-machine parser; tag/attribute names compared case-
* insensitively against the allowlist; `<a href>` / `<… src>` URL schemes
* validated (http, https, mailto, fragment-only, or relative); whole-
* subtree drop for script / style / iframe / object / embed / form; HTML-
* escapes free text outside dropped subtrees.
*
* The allowlist is JSON of the form
* {"p":[],"a":["href","title"],"strong":[],...}
* where each value is the array of attribute names allowed for that tag. */
el_val_t el_html_sanitize(el_val_t input_html, el_val_t allowlist_json);
/* ── Filesystem ──────────────────────────────────────────────────────────── */
el_val_t fs_read(el_val_t path);
el_val_t fs_write(el_val_t path, el_val_t content);
el_val_t fs_list(el_val_t path);
el_val_t fs_exists(el_val_t path);
el_val_t fs_mkdir(el_val_t path); /* mkdir -p, mode 0755 */
/* Length-explicit binary write. `length` is an Int (el_val_t holding the
* byte count). The caller knows the length from context — typically because
* `bytes` came from base64_decode (which produces a magic-tagged binary
* buffer with embedded NULs possible) and the caller already tracks the
* decoded length, OR because the bytes came from a fixed-size source
* (sha256_bytes = 32, hmac_sha256_bytes = 32). Bypasses strlen entirely.
*
* Returns 1 on success, 0 on failure (invalid path, can't open, partial
* write, negative length). On partial-write failure, the file is removed
* so callers cannot read back a truncated artefact. */
el_val_t fs_write_bytes(el_val_t path, el_val_t bytes, el_val_t length);
/* ── JSON ────────────────────────────────────────────────────────────────── */
el_val_t json_get(el_val_t json, el_val_t key);
el_val_t json_parse(el_val_t s);
el_val_t json_stringify(el_val_t v);
el_val_t json_get_string(el_val_t json_str, el_val_t key);
el_val_t json_get_int(el_val_t json_str, el_val_t key);
el_val_t json_get_float(el_val_t json_str, el_val_t key);
el_val_t json_get_bool(el_val_t json_str, el_val_t key);
el_val_t json_get_raw(el_val_t json_str, el_val_t key);
el_val_t json_set(el_val_t json_str, el_val_t key, el_val_t value);
el_val_t json_array_len(el_val_t json_str);
el_val_t json_array_get(el_val_t json_str, el_val_t index);
el_val_t json_array_get_string(el_val_t json_str, el_val_t index);
/* ── Time ────────────────────────────────────────────────────────────────── */
el_val_t time_now(void);
el_val_t time_now_utc(void);
el_val_t sleep_secs(el_val_t secs);
el_val_t sleep_ms(el_val_t ms);
el_val_t time_format(el_val_t ts, el_val_t fmt);
el_val_t time_to_parts(el_val_t ts);
el_val_t time_from_parts(el_val_t secs, el_val_t ns, el_val_t tz);
el_val_t time_add(el_val_t ts, el_val_t n, el_val_t unit);
el_val_t time_diff(el_val_t ts1, el_val_t ts2, el_val_t unit);
/* ── Instant + Duration: first-class temporal types ──────────────────────────
* Both types share the el_val_t (int64) slot. Instants are nanoseconds
* since the Unix epoch; Durations are signed nanoseconds. Type discipline
* is enforced at codegen-time: BinOps on names registered as Instant or
* Duration route through the typed wrappers below; mismatches like
* Instant+Instant become #error at the C compiler.
*
* Postfix literals — `30.seconds`, `1.hour`, `500.millis`, `30.nanos` — are
* recognised by the parser as DurationLit AST nodes and lowered to literal
* int64 nanoseconds at codegen time. The runtime never sees the units. */
el_val_t el_now_instant(void);
el_val_t now(void);
el_val_t unix_seconds(el_val_t n);
el_val_t unix_millis(el_val_t n);
el_val_t instant_from_iso8601(el_val_t s);
el_val_t el_duration_from_nanos(el_val_t ns);
el_val_t duration_seconds(el_val_t n);
el_val_t duration_millis(el_val_t n);
el_val_t duration_nanos(el_val_t n);
el_val_t el_instant_add_dur(el_val_t inst, el_val_t dur);
el_val_t el_instant_sub_dur(el_val_t inst, el_val_t dur);
el_val_t el_instant_diff(el_val_t a, el_val_t b);
el_val_t el_duration_add(el_val_t a, el_val_t b);
el_val_t el_duration_sub(el_val_t a, el_val_t b);
el_val_t el_duration_scale(el_val_t dur, el_val_t scalar);
el_val_t el_duration_div(el_val_t dur, el_val_t scalar);
el_val_t el_instant_lt(el_val_t a, el_val_t b);
el_val_t el_instant_le(el_val_t a, el_val_t b);
el_val_t el_instant_gt(el_val_t a, el_val_t b);
el_val_t el_instant_ge(el_val_t a, el_val_t b);
el_val_t el_instant_eq(el_val_t a, el_val_t b);
el_val_t el_instant_ne(el_val_t a, el_val_t b);
el_val_t el_duration_lt(el_val_t a, el_val_t b);
el_val_t el_duration_le(el_val_t a, el_val_t b);
el_val_t el_duration_gt(el_val_t a, el_val_t b);
el_val_t el_duration_ge(el_val_t a, el_val_t b);
el_val_t el_duration_eq(el_val_t a, el_val_t b);
el_val_t el_duration_ne(el_val_t a, el_val_t b);
el_val_t instant_to_unix_seconds(el_val_t i);
el_val_t instant_to_unix_millis(el_val_t i);
el_val_t instant_to_iso8601(el_val_t i);
el_val_t duration_to_seconds(el_val_t d);
el_val_t duration_to_millis(el_val_t d);
el_val_t duration_to_nanos(el_val_t d);
el_val_t el_sleep_duration(el_val_t dur);
el_val_t unix_timestamp(void);
el_val_t ttl_cache_set(el_val_t key, el_val_t value);
el_val_t ttl_cache_get(el_val_t key, el_val_t max_age);
el_val_t ttl_cache_age(el_val_t key);
/* ── Calendar + CalendarTime + Rhythm + LocalDate/Time/DateTime ─────────────
* Phase 1.5 of the time system. Calendar is pluggable: EarthCalendar (IANA
* zones, Gregorian, DST) is the user-facing default; MarsCalendar,
* CycleCalendar(period), NoCycleCalendar, RelativeCalendar handle non-Earth
* domains.
*
* A Calendar interprets an Instant under a particular cycle convention and
* produces a CalendarTime. CalendarTime carries the underlying Instant and
* a back-pointer to its Calendar; arithmetic and formatting consult the
* Calendar to convert ns since epoch into year/month/day/hour/minute/second
* (or sol/phase, or cycle/phase, depending on kind).
*
* Storage convention: Calendar / CalendarTime / Rhythm / LocalDate /
* LocalDateTime are heap-allocated structs whose pointers are cast into
* el_val_t. A 24-bit magic header at offset 0 lets the runtime identify
* the kind safely. LocalTime is small enough to live in the int64 slot
* directly (nanos since midnight, signed). */
/* Zone — opaque IANA zone or fixed offset, used by EarthCalendar.
* `zone_id` is either an IANA name ("America/New_York", "UTC") or a fixed
* offset string ("+05:30", "-08:00"). The runtime resolves it via tzset()
* on first use of the owning EarthCalendar. */
el_val_t zone(el_val_t id);
el_val_t zone_utc(void);
el_val_t zone_local(void);
el_val_t zone_offset(el_val_t hours, el_val_t minutes);
/* Calendar constructors. Each returns an el_val_t pointer to a heap-
* allocated, magic-tagged Calendar struct. Calendars are interned by
* (kind, zone_id, period_ns, epoch_ns) so identical constructors return
* the same pointer — equality is reference equality. */
el_val_t earth_calendar(el_val_t z);
el_val_t earth_calendar_default(void);
el_val_t mars_calendar(void);
el_val_t cycle_calendar(el_val_t period_dur);
el_val_t no_cycle_calendar(void);
el_val_t relative_calendar(el_val_t epoch_inst);
/* CalendarTime constructors and methods. Returns a heap-allocated struct
* whose pointer fits in el_val_t. */
el_val_t now_in(el_val_t cal);
el_val_t in_calendar(el_val_t inst, el_val_t cal);
el_val_t cal_format(el_val_t ct, el_val_t pattern);
el_val_t cal_to_instant(el_val_t ct);
el_val_t cal_cycle_phase(el_val_t ct);
el_val_t cal_in(el_val_t ct, el_val_t cal);
/* LocalDate / LocalTime / LocalDateTime — calendar-agnostic value types.
* LocalTime carries nanoseconds since midnight as a signed int64 directly
* in the el_val_t slot (no allocation). LocalDate / LocalDateTime are
* heap-allocated structs with magic headers. */
el_val_t local_date(el_val_t y, el_val_t m, el_val_t d);
el_val_t local_time(el_val_t h, el_val_t m, el_val_t s, el_val_t ns);
el_val_t local_datetime(el_val_t date, el_val_t time);
el_val_t zoned(el_val_t date, el_val_t time, el_val_t cal);
el_val_t local_date_year(el_val_t ld);
el_val_t local_date_month(el_val_t ld);
el_val_t local_date_day(el_val_t ld);
el_val_t local_time_hour(el_val_t lt);
el_val_t local_time_minute(el_val_t lt);
el_val_t local_time_second(el_val_t lt);
el_val_t local_time_nanos(el_val_t lt);
el_val_t el_local_date_add_dur(el_val_t ld, el_val_t dur);
el_val_t el_local_time_add_dur(el_val_t lt, el_val_t dur);
el_val_t el_local_date_lt(el_val_t a, el_val_t b);
el_val_t el_local_date_eq(el_val_t a, el_val_t b);
/* Rhythm — pluggable recurrence AST. Returns a heap-allocated struct
* pointer in el_val_t; rhythms are immutable so callers may share them. */
el_val_t rhythm_cycle_start(void);
el_val_t rhythm_cycle_phase(el_val_t phase);
el_val_t rhythm_duration(el_val_t d);
el_val_t rhythm_session_start(void);
el_val_t rhythm_event(el_val_t name);
el_val_t rhythm_and(el_val_t a, el_val_t b);
el_val_t rhythm_or(el_val_t a, el_val_t b);
el_val_t rhythm_weekday(el_val_t day);
el_val_t rhythm_weekly_at(el_val_t day, el_val_t hour, el_val_t minute);
el_val_t rhythm_next_after(el_val_t r, el_val_t after, el_val_t cal);
el_val_t rhythm_matches(el_val_t r, el_val_t ct);
/* ── UUID ────────────────────────────────────────────────────────────────── */
el_val_t uuid_new(void);
el_val_t uuid_v4(void);
/* ── Environment ─────────────────────────────────────────────────────────── */
el_val_t env(el_val_t key);
/* ── In-process state K/V ────────────────────────────────────────────────── */
el_val_t state_set(el_val_t key, el_val_t value);
el_val_t state_get(el_val_t key);
el_val_t state_del(el_val_t key);
el_val_t state_keys(void);
/* ── Float formatting ────────────────────────────────────────────────────── */
el_val_t float_to_str(el_val_t f);
el_val_t int_to_float(el_val_t n);
el_val_t float_to_int(el_val_t f);
el_val_t format_float(el_val_t f, el_val_t decimals);
el_val_t decimal_round(el_val_t f, el_val_t decimals);
el_val_t str_to_float(el_val_t s);
/* ── Math (Float-aware) ──────────────────────────────────────────────────── */
el_val_t math_sqrt(el_val_t f);
el_val_t math_log(el_val_t f);
el_val_t math_ln(el_val_t f);
el_val_t math_sin(el_val_t f);
el_val_t math_cos(el_val_t f);
el_val_t math_pi(void);
/* ── String additions ────────────────────────────────────────────────────── */
el_val_t str_index_of(el_val_t s, el_val_t sub);
el_val_t str_split(el_val_t s, el_val_t sep);
el_val_t str_char_at(el_val_t s, el_val_t i);
el_val_t str_char_code(el_val_t s, el_val_t i);
el_val_t str_pad_left(el_val_t s, el_val_t width, el_val_t pad);
el_val_t str_pad_right(el_val_t s, el_val_t width, el_val_t pad);
el_val_t str_format(el_val_t fmt, el_val_t data);
el_val_t str_lower(el_val_t s);
el_val_t str_upper(el_val_t s);
/* ── Text-processing primitives (Phase 1: byte/codepoint, ASCII char classes)
* Phase 2 (filed): Unicode-grapheme awareness, NFC/NFD normalization, regex.
* is_* predicates: empty input returns false; multi-char requires ALL bytes
* to match. ASCII ranges only in Phase 1. */
/* Counting */
el_val_t str_count(el_val_t s, el_val_t sub); /* non-overlapping */
el_val_t str_count_chars(el_val_t s); /* codepoint count */
el_val_t str_count_bytes(el_val_t s); /* alias of str_len */
el_val_t str_count_lines(el_val_t s);
el_val_t str_count_words(el_val_t s);
el_val_t str_count_letters(el_val_t s); /* ASCII [A-Za-z] */
el_val_t str_count_digits(el_val_t s); /* ASCII [0-9] */
/* Find / position */
el_val_t str_index_of_all(el_val_t s, el_val_t sub); /* [Int] of byte offsets */
el_val_t str_last_index_of(el_val_t s, el_val_t sub);
el_val_t str_find_chars(el_val_t s, el_val_t any_of); /* first idx of any ch */
/* Transform */
el_val_t str_repeat(el_val_t s, el_val_t n);
el_val_t str_reverse(el_val_t s); /* by codepoint */
el_val_t str_strip_prefix(el_val_t s, el_val_t prefix);
el_val_t str_strip_suffix(el_val_t s, el_val_t suffix);
el_val_t str_strip_chars(el_val_t s, el_val_t chars);
el_val_t str_lstrip(el_val_t s);
el_val_t str_rstrip(el_val_t s);
/* Char classification (Bool) */
el_val_t is_letter(el_val_t s);
el_val_t is_digit(el_val_t s);
el_val_t is_alphanumeric(el_val_t s);
el_val_t is_whitespace(el_val_t s);
el_val_t is_punctuation(el_val_t s);
el_val_t is_uppercase(el_val_t s);
el_val_t is_lowercase(el_val_t s);
/* Split / join */
el_val_t str_split_lines(el_val_t s);
el_val_t str_split_chars(el_val_t s); /* alias of native_string_chars */
el_val_t str_split_n(el_val_t s, el_val_t sep, el_val_t n);
el_val_t str_join(el_val_t list, el_val_t sep); /* alias of list_join */
/* ── List additions ──────────────────────────────────────────────────────── */
el_val_t list_push(el_val_t list, el_val_t elem);
el_val_t list_push_front(el_val_t list, el_val_t elem);
el_val_t list_join(el_val_t list, el_val_t sep);
el_val_t list_range(el_val_t start, el_val_t end);
/* ── Bool helpers ────────────────────────────────────────────────────────── */
el_val_t bool_to_str(el_val_t b);
/* ── Numeric parsing ─────────────────────────────────────────────────────── */
el_val_t parse_int(el_val_t s, el_val_t default_val);
/* ── Process ─────────────────────────────────────────────────────────────── */
void exit_program(el_val_t code);
el_val_t getpid_now(void);
/* ── CGI identity ─────────────────────────────────────────────────────────────
* Called at the start of main() in CGI programs (those with a `cgi {}` block).
* Records the program's DHARMA identity before any other code executes. */
void el_cgi_init(el_val_t name, el_val_t dharma_id, el_val_t principal,
el_val_t network, el_val_t engram);
/* ── DHARMA network builtins ─────────────────────────────────────────────────
* Available to CGI programs (declared with a `cgi {}` block).
*
* Peers are addressed by `dharma_id` of the form
* "<registry-id>@<transport-url>" e.g. "ntn-genesis@http://localhost:7770"
* If the @<url> portion is omitted, transport defaults to
* "http://localhost:7770" (the local CGI daemon assumption).
*
* Wire protocol (all peers expose):
* POST <url>/dharma/recv { channel, from, content } → response body
* POST <url>/dharma/event { type, payload, source, timestamp }
* POST <url>/api/activate { query } → list of nodes
*
* Hosting application's responsibility: an El program with a `cgi {}` block
* runs http_serve() with its own request handler; that handler should route
* "/dharma/event" requests by calling el_runtime_dharma_event_arrive() so
* incoming events feed dharma_field() queues. The runtime itself does not
* intercept any /dharma path. */
el_val_t dharma_connect(el_val_t cgi_id);
el_val_t dharma_send(el_val_t channel, el_val_t content);
el_val_t dharma_activate(el_val_t query);
void dharma_emit(el_val_t event_type, el_val_t payload);
el_val_t dharma_field(el_val_t event_type);
void dharma_strengthen(el_val_t cgi_id, el_val_t weight);
el_val_t dharma_relationship(el_val_t cgi_id);
el_val_t dharma_peers(void);
/* Public C API: called by an El program's HTTP handler when a /dharma/event
* request arrives. Pushes onto the per-event-type queue and signals any
* pending dharma_field() blockers. All three arguments must be NUL-terminated
* C strings (or NULL — then treated as empty). */
void el_runtime_dharma_event_arrive(const char* event_type,
const char* payload,
const char* source);
/* ── Engram local graph primitives ───────────────────────────────────────────
* Operate on the CGI's local Engram knowledge graph.
* `engram_activate` queries the local graph only; `dharma_activate` is
* network-wide across all connected CGI graphs. */
el_val_t engram_node(el_val_t content, el_val_t node_type, el_val_t salience);
el_val_t engram_node_full(el_val_t content, el_val_t node_type, el_val_t label,
el_val_t salience, el_val_t importance, el_val_t confidence,
el_val_t tier, el_val_t tags);
/* Layered consciousness — see el_runtime.c for the layered architecture
* design notes (search "Layered consciousness architecture"). The five
* canonical layers (safety / core-identity / domain-knowledge / imprint /
* suit) are seeded automatically; engram_add_layer extends the registry
* with imprint or suit overlays at runtime. Nodes default to layer 1
* (core-identity) when created via engram_node / engram_node_full. */
el_val_t engram_node_layered(el_val_t content, el_val_t node_type, el_val_t label,
el_val_t salience, el_val_t certainty, el_val_t confidence,
el_val_t status, el_val_t tags, el_val_t layer_id);
el_val_t engram_add_layer(el_val_t name, el_val_t priority, el_val_t suppressible,
el_val_t transparent, el_val_t injectable);
el_val_t engram_remove_layer(el_val_t layer_id);
el_val_t engram_list_layers(void);
el_val_t engram_get_node(el_val_t id);
void engram_strengthen(el_val_t node_id);
void engram_forget(el_val_t node_id);
el_val_t engram_prune_telemetry(el_val_t older_than_ms);
el_val_t engram_node_count(void);
el_val_t engram_search(el_val_t query, el_val_t limit);
el_val_t engram_scan_nodes(el_val_t limit, el_val_t offset);
void engram_connect(el_val_t from_id, el_val_t to_id, el_val_t weight, el_val_t relation);
el_val_t engram_edge_between(el_val_t from_id, el_val_t to_id);
el_val_t engram_neighbors(el_val_t node_id);
el_val_t engram_neighbors_filtered(el_val_t node_id, el_val_t max_depth, el_val_t direction);
el_val_t engram_edge_count(void);
/* Three-pass activation: background fan-out → working-memory promotion →
* Layer 0 override. See "Three-pass activation" in el_runtime.c. */
el_val_t engram_activate(el_val_t query, el_val_t depth);
el_val_t engram_save(el_val_t path);
el_val_t engram_load(el_val_t path);
/* JSON-string accessors — return pre-serialized JSON so HTTP handlers
* can pass results straight through without round-tripping ElList/ElMap
* through json_stringify. */
el_val_t engram_get_node_json(el_val_t id);
el_val_t engram_get_node_by_label(el_val_t label);
el_val_t engram_search_json(el_val_t query, el_val_t limit);
el_val_t engram_scan_nodes_json(el_val_t limit, el_val_t offset);
el_val_t engram_scan_nodes_by_type_json(el_val_t node_type, el_val_t limit, el_val_t offset);
el_val_t engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t direction);
el_val_t engram_activate_json(el_val_t query, el_val_t depth);
el_val_t engram_stats_json(void);
el_val_t engram_list_layers_json(void);
/* Working memory introspection — count, mean weight, and top-N snapshot.
* Ported from el-compiler/runtime on 2026-06-30 self-review. */
el_val_t engram_wm_count(void);
el_val_t engram_wm_avg_weight(void);
el_val_t engram_wm_top_json(el_val_t n);
/* Merge-load: add nodes/edges from a snapshot without resetting the store. */
el_val_t engram_load_merge(el_val_t path);
/* engram_compile_layered_json — produce a prompt-ready text block split
* into "[LAYER 0 — STRUCTURAL]" (non-suppressible layers, sacred fire)
* and "[ENGRAM CONTEXT]" (standard suppressible layers). Returns "" if
* no nodes promoted to working memory. */
el_val_t engram_compile_layered_json(el_val_t intent, el_val_t depth);
/* ── LLM (Anthropic API client) ─────────────────────────────────────────────
* All functions call https://api.anthropic.com/v1/messages with the API key
* from env ANTHROPIC_API_KEY. Default model when empty: claude-sonnet-4-5. */
el_val_t llm_call(el_val_t model, el_val_t prompt);
el_val_t llm_call_system(el_val_t model, el_val_t system_prompt, el_val_t user_prompt);
el_val_t llm_call_agentic(el_val_t model, el_val_t system, el_val_t user, el_val_t tools);
el_val_t llm_vision(el_val_t model, el_val_t system, el_val_t prompt, el_val_t image_url_or_b64);
el_val_t llm_models(void);
/* Register a tool handler by name. The handler is looked up via dlsym
* (mirroring http_set_handler), so any El `fn <name>(input)` compiles to
* a global C symbol that this function can locate at runtime.
* Handler signature: `el_val_t handler(el_val_t input_json)` — receives
* the tool input as a JSON-string el_val_t and returns a JSON-string
* el_val_t result. Used by llm_call_agentic. */
void llm_register_tool(el_val_t name, el_val_t handler_fn_name);
/* ── args() ─────────────────────────────────────────────────────────────────
* Provides access to command-line arguments passed to the program.
* Populated by el_runtime_init_args() before main() runs. */
el_val_t args(void);
void el_runtime_init_args(int argc, char** argv);
/* ── Crypto primitives ─────────────────────────────────────────────────────
* SHA-256, HMAC-SHA-256, and base64 (standard + URL-safe).
* Self-contained — no OpenSSL/libcrypto dependency. The implementations are
* adapted from public-domain reference code (Brad Conte / RFC 4648).
*
* Bytes-returning variants (sha256_bytes, hmac_sha256_bytes) return a string
* value whose contents are raw binary; callers usually feed these into
* base64_encode. Note that el_val_t strings are NUL-terminated by convention,
* so the binary payload may contain embedded NULs — pass it directly into
* base64_encode (which uses an explicit length) rather than treating it as
* a printable C string.
*
* The "base64" variants emit/accept RFC 4648 standard alphabet with padding.
* The "base64url" variants use URL-safe alphabet (`-`/`_`) with no padding,
* as used in JWTs. */
el_val_t sha256_hex(el_val_t input);
el_val_t sha256_bytes(el_val_t input);
el_val_t hmac_sha256_hex(el_val_t key, el_val_t message);
el_val_t hmac_sha256_bytes(el_val_t key, el_val_t message);
el_val_t base64_encode(el_val_t input);
el_val_t base64_decode(el_val_t input);
el_val_t base64url_encode(el_val_t input);
el_val_t base64url_decode(el_val_t input);
/* Length-aware variants (internal — exposed for the rare caller that already
* has a known-length binary buffer and doesn't want to round-trip through
* a NUL-terminated el_val_t string). Sha256_bytes and hmac_sha256_bytes feed
* these implicitly. */
el_val_t el_sha256_bytes_n(const unsigned char* data, size_t len);
el_val_t el_base64_encode_n(const unsigned char* data, size_t len, int url_safe);
/* ── Post-quantum primitives (liboqs-backed) ────────────────────────────────
* All inputs/outputs hex-encoded. Algorithm choices:
* Signature: CRYSTALS-Dilithium-3 (NIST level 3, balanced)
* KEM: CRYSTALS-Kyber-768 (NIST level 3)
* Hash: SHA3-256 (Keccak) (PQ-aware protocols favour SHA3 over SHA2)
*
* If liboqs is not linked (detected via __has_include(<oqs/oqs.h>) at compile
* time), the pq_* entry points return a JSON-shaped error string so callers
* fail loudly rather than silently fall back to classical schemes:
* {"error":"liboqs not linked, post-quantum primitives unavailable"}
*
* The hybrid handshake pairs X25519 with Kyber-768 per NIST PQ guidance and
* CNSA 2.0. Combined shared secret is HKDF-SHA256(x25519_ss || kyber_ss).
* Even if Kyber falls, X25519 holds; if X25519 falls under quantum attack,
* Kyber holds. SHA3-256 also remains usable independent of liboqs (the
* Keccak permutation is PQ-OK as a primitive). */
el_val_t pq_keygen_signature(void);
el_val_t pq_sign(el_val_t secret_key_hex, el_val_t message);
el_val_t pq_verify(el_val_t public_key_hex, el_val_t message, el_val_t signature_hex);
el_val_t pq_kem_keygen(void);
el_val_t pq_kem_encaps(el_val_t public_key_hex);
el_val_t pq_kem_decaps(el_val_t secret_key_hex, el_val_t ciphertext_hex);
el_val_t pq_hybrid_keygen(void);
el_val_t pq_hybrid_handshake(el_val_t remote_pub_combined);
el_val_t sha3_256_hex(el_val_t input);
/* ── AEAD: AES-256-GCM (libcrypto-backed) ───────────────────────────────────
* Symmetric authenticated encryption used to wrap envelopes after a KEM
* handshake. Caller MUST supply a 32-byte key (64 hex chars) — typically the
* Kyber-768 / hybrid shared_secret, optionally normalized via SHA3-256.
*
* aead_encrypt returns a JSON map {"nonce":"...","ciphertext":"..."} where
* ciphertext is the AES-256-GCM output with the 16-byte auth tag appended.
* Nonce is a fresh 12-byte CSPRNG draw — callers never pick the nonce, which
* structurally rules out the GCM nonce-reuse footgun.
*
* aead_decrypt returns the plaintext String, or "" on any failure (including
* auth-tag mismatch). Callers MUST check for "" before trusting the result. */
el_val_t aead_encrypt(el_val_t key_hex, el_val_t plaintext);
el_val_t aead_decrypt(el_val_t key_hex, el_val_t nonce_hex, el_val_t ciphertext_hex);
/* ── Native VM builtin aliases (for compiled El source) ─────────────────────
* These match the El VM's native_* builtins so that El source compiled
* to C can call the same names without modification. */
el_val_t native_list_get(el_val_t list, el_val_t index);
el_val_t native_list_len(el_val_t list);
el_val_t native_list_append(el_val_t list, el_val_t elem);
el_val_t native_list_empty(void);
el_val_t native_list_clone(el_val_t list);
el_val_t native_string_chars(el_val_t s);
el_val_t native_int_to_str(el_val_t n);
/* ── Method-call shorthand aliases ──────────────────────────────────────────
* The El method-call convention `obj.method(args)` compiles to
* `method(obj, args)`. These aliases expose the runtime functions under
* the short names that result from method calls in El source.
*
* Example: `myList.append(x)` → `append(myList, x)` (calls this alias)
* `myList.len()` → `len(myList)` (calls this alias) */
el_val_t append(el_val_t list, el_val_t elem); /* el_list_append */
el_val_t len(el_val_t list); /* el_list_len */
el_val_t get(el_val_t list, el_val_t index); /* el_list_get */
el_val_t map_get(el_val_t map, el_val_t key); /* el_map_get */
el_val_t map_set(el_val_t map, el_val_t key, el_val_t value); /* el_map_set */
/* ── OTLP/HTTP Observability ─────────────────────────────────────────────── */
/* See bottom of el_runtime.c for the implementation.
* Configured by env vars OTLP_ENDPOINT, OTEL_SERVICE_NAME, OTEL_SERVICE_VERSION.
* No-op when OTLP_ENDPOINT is unset. Drop-on-failure semantics. */
/* ── Subprocess execution ────────────────────────────────────────────────── */
el_val_t exec_command(el_val_t cmd); /* run shell command, return exit code */
el_val_t exec_capture(el_val_t cmd); /* run shell command, capture stdout */
el_val_t exec(el_val_t cmd); /* exec(cmd) → stdout String (30s timeout) */
el_val_t exec_bg(el_val_t cmd); /* exec_bg(cmd) → PID String (non-blocking) */
el_val_t emit_log(el_val_t level, el_val_t msg, el_val_t fields_json);
el_val_t emit_metric(el_val_t name, el_val_t value, el_val_t tags_json);
el_val_t trace_span_start(el_val_t name);
el_val_t trace_span_end(el_val_t span_handle);
el_val_t emit_event(el_val_t name, el_val_t duration_ms);
#ifdef __cplusplus
}
#endif