El data studio: 10-loop improvement pass — full Engram DB explorer

Full-featured terminal explorer for the Engram knowledge graph built
natively in El. Features:
- ANSI-colored TUI with box-drawing borders and salience bars
- All API endpoints: stats, nodes by type/tier, search, edges,
  spreading activation, node detail with neighbor traversal
- Text report export via fs_write
- Offline/unreachable mode with helpful startup messages
- Interactive mode command reference
- ENGRAM_URL env var for connecting to non-default servers
- Uses json_get_raw for nested JSON object traversal
This commit is contained in:
Will Anderson
2026-04-29 04:39:40 -05:00
commit 0b480cfb6b
4 changed files with 1143 additions and 0 deletions
+787
View File
@@ -0,0 +1,787 @@
//
// ENGRAM DATA STUDIO Native El Application
// Full-featured terminal explorer for the Engram knowledge graph
//
//
// Usage: el run-file studio.el
// ENGRAM_URL=http://host:port el run-file studio.el
//
// Requires: Engram server running (default: http://localhost:8340)
// Configuration
fn get_base_url() -> String {
let e: String = env("ENGRAM_URL")
if e == "" {
return "http://localhost:8340"
}
return e
}
fn get_report_path() -> String {
let e: String = env("ENGRAM_REPORT")
if e == "" {
return "/tmp/engram-studio-report.txt"
}
return e
}
// Box-drawing helpers
fn repeat_str(s: String, n: Int) -> String {
let result: String = ""
let i: Int = 0
while i < n {
let result: String = result + s
let i: Int = i + 1
}
return result
}
fn hline(width: Int) -> String {
return repeat_str("", width)
}
fn box_top(width: Int) -> String {
return "" + hline(width) + ""
}
fn box_bot(width: Int) -> String {
return "" + hline(width) + ""
}
fn box_row(content: String, width: Int) -> String {
let padded: String = str_pad_right(content, width, " ")
return "" + padded + ""
}
fn double_top(width: Int) -> String {
return "" + repeat_str("", width) + ""
}
fn double_bot(width: Int) -> String {
return "" + repeat_str("", width) + ""
}
fn double_row(content: String, width: Int) -> String {
let padded: String = str_pad_right(content, width, " ")
return "" + padded + ""
}
fn section_header(title: String) -> String {
println("")
println(color_bold(box_top(62)))
println(color_bold(box_row(" " + title, 62)))
println(color_bold(box_bot(62)))
return ""
}
fn divider() -> String {
println(color_dim(" " + repeat_str("·", 58)))
return ""
}
// API access
fn api_get(path: String) -> String {
let url: String = get_base_url() + path
let resp: String = http_get(url)
if str_starts_with(resp, "{\"error\"") {
return ""
}
return resp
}
fn api_post(path: String, body: String) -> String {
let url: String = get_base_url() + path
let resp: String = http_post(url, body)
if str_starts_with(resp, "{\"error\"") {
return ""
}
return resp
}
// Safe JSON field extractors
// These handle both raw JSON strings and parsed Value::Struct objects.
fn safe_str(node: String, key: String) -> String {
return json_get_string(node, key)
}
fn safe_int(node: String, key: String) -> Int {
return json_get_int(node, key)
}
fn safe_float(node: String, key: String) -> Float {
return json_get_float(node, key)
}
// Formatting helpers
fn short_id(full_id: String) -> String {
if str_len(full_id) >= 8 {
return str_slice(full_id, 0, 8)
}
return full_id
}
fn format_bytes(n: Int) -> String {
if n < 1024 {
return int_to_str(n) + " B"
}
if n < 1048576 {
let kb: Int = n / 1024
return int_to_str(kb) + " KB"
}
let mb: Int = n / 1048576
return int_to_str(mb) + " MB"
}
fn format_timestamp(ms: Int) -> String {
if ms <= 0 {
return ""
}
let secs: Int = ms / 1000
let ts: Int = time_from_parts(secs, 0, "UTC")
return time_format(ts, "ISO")
}
fn content_preview(content: String, max_len: Int) -> String {
let n: Int = str_len(content)
if n == 0 {
return color_dim("(no content)")
}
if n <= max_len {
return content
}
return str_slice(content, 0, max_len) + color_dim("")
}
fn salience_bar(salience: Float) -> String {
let pct: Float = salience * 10.0
let filled: Int = float_to_int(pct)
let bar: String = repeat_str("", filled) + repeat_str("", 10 - filled)
if salience >= 0.7 {
return color_green(bar)
}
if salience >= 0.4 {
return color_yellow(bar)
}
return color_dim(bar)
}
fn tier_badge(tier: String) -> String {
if tier == "Semantic" {
return color_cyan("[Semantic ]")
}
if tier == "Episodic" {
return color_yellow("[Episodic ]")
}
if tier == "Working" {
return color_green("[Working ]")
}
if tier == "Procedural" {
return color_bold("[Procedural]")
}
return "[" + str_pad_right(tier, 10, " ") + "]"
}
fn type_badge(node_type: String) -> String {
if node_type == "Memory" {
return color_cyan("Memory ")
}
if node_type == "Concept" {
return color_green("Concept ")
}
if node_type == "Event" {
return color_yellow("Event ")
}
if node_type == "Entity" {
return color_bold("Entity ")
}
if node_type == "Process" {
return color_cyan("Process ")
}
if node_type == "InternalState" {
return color_dim("IntState ")
}
return str_pad_right(node_type, 10, " ")
}
// Node renderer
fn render_node_row(node_json: String, idx: Int) -> String {
let id: String = short_id(safe_str(node_json, "id"))
let label: String = safe_str(node_json, "label")
let node_type: String = safe_str(node_json, "node_type")
let tier: String = safe_str(node_json, "tier")
let salience: Float = safe_float(node_json, "salience")
let label_col: String = str_pad_right(label, 36, " ")
let sal_str: String = format_float(salience, 3)
let num: String = str_pad_left(int_to_str(idx + 1), 3, " ") + ". "
return " " + num + color_dim(id) + " " + label_col + " " + type_badge(node_type) + " " + sal_str
}
fn render_node_detail(node_json: String) -> String {
let id: String = safe_str(node_json, "id")
let label: String = safe_str(node_json, "label")
let node_type: String = safe_str(node_json, "node_type")
let tier: String = safe_str(node_json, "tier")
let salience: Float = safe_float(node_json, "salience")
let importance: Float = safe_float(node_json, "importance")
let confidence: Float = safe_float(node_json, "confidence")
let created: Int = safe_int(node_json, "created_at")
let updated: Int = safe_int(node_json, "updated_at")
println(" " + color_bold("ID: ") + id)
println(" " + color_bold("Label: ") + color_cyan(label))
println(" " + color_bold("Type: ") + node_type)
println(" " + color_bold("Tier: ") + tier_badge(tier))
println(" " + color_bold("Salience: ") + salience_bar(salience) + " " + format_float(salience, 4))
println(" " + color_bold("Importance: ") + format_float(importance, 4))
println(" " + color_bold("Confidence: ") + format_float(confidence, 4))
println(" " + color_bold("Created: ") + color_dim(format_timestamp(created)))
println(" " + color_bold("Updated: ") + color_dim(format_timestamp(updated)))
return ""
}
// Section: Stats Dashboard
fn show_stats(report: String) -> String {
section_header("Database Statistics")
let stats_json: String = api_get("/api/stats")
if stats_json == "" {
println(" " + color_red("Error: could not reach Engram server"))
println(" Make sure the server is running: engram-server --data-dir <path>")
return report
}
let node_count: Int = safe_int(stats_json, "node_count")
let edge_count: Int = safe_int(stats_json, "edge_count")
let avg_sal: Float = safe_float(stats_json, "avg_salience")
let db_bytes: Int = safe_int(stats_json, "db_size_bytes")
println(" " + color_bold("Nodes: ") + color_cyan(int_to_str(node_count)))
println(" " + color_bold("Edges: ") + color_cyan(int_to_str(edge_count)))
println(" " + color_bold("Avg Salience: ") + format_float(avg_sal, 4))
println(" " + color_bold("DB Size: ") + color_dim(format_bytes(db_bytes)))
let new_report: String = report
+ "\n=== Database Statistics ===\n"
+ "Nodes: " + int_to_str(node_count) + "\n"
+ "Edges: " + int_to_str(edge_count) + "\n"
+ "Avg Salience: " + format_float(avg_sal, 4) + "\n"
+ "DB Size: " + format_bytes(db_bytes) + "\n"
return new_report
}
// Section: Node Browser
fn show_nodes(node_type: String, limit: Int, report: String) -> String {
let title: String = "Nodes — type: " + node_type
section_header(title)
let path: String = "/api/nodes?node_type=" + node_type + "&limit=" + int_to_str(limit)
let json_str: String = api_get(path)
if json_str == "" {
println(" " + color_dim("No nodes found or server unreachable"))
return report
}
let nodes: List = json_parse(json_str)
let n: Int = list_len(nodes)
if n == 0 {
println(" " + color_dim("(no " + node_type + " nodes)"))
return report
}
println(" " + color_dim("Showing " + int_to_str(n) + " nodes:"))
println("")
let header: String = " " + str_pad_right(" # ID Label", 55, " ") + " Type Salience"
println(color_dim(header))
println(color_dim(" " + repeat_str("", 70)))
let i: Int = 0
let report_section: String = "\n=== " + node_type + " Nodes ===\n"
while i < n {
let node: String = json_stringify(list_get(nodes, i))
println(render_node_row(node, i))
let label: String = safe_str(node, "label")
let id: String = short_id(safe_str(node, "id"))
let sal: Float = safe_float(node, "salience")
let report_section: String = report_section + int_to_str(i + 1) + ". [" + id + "] " + label + " (sal=" + format_float(sal, 3) + ")\n"
let i: Int = i + 1
}
return report + report_section
}
// Section: Recent Nodes
fn show_recent(limit: Int, report: String) -> String {
section_header("Recent Nodes (last " + int_to_str(limit) + ")")
let path: String = "/api/nodes?limit=" + int_to_str(limit)
let json_str: String = api_get(path)
if json_str == "" {
println(" " + color_dim("No nodes or server unreachable"))
return report
}
let nodes: List = json_parse(json_str)
let n: Int = list_len(nodes)
if n == 0 {
println(" " + color_dim("(database is empty)"))
return report
}
println(" " + color_dim("Showing " + int_to_str(n) + " most recent nodes:"))
println("")
let header: String = " " + str_pad_right(" # ID Label", 55, " ") + " Type Salience"
println(color_dim(header))
println(color_dim(" " + repeat_str("", 70)))
let i: Int = 0
let report_section: String = "\n=== Recent Nodes ===\n"
while i < n {
let node: String = json_stringify(list_get(nodes, i))
println(render_node_row(node, i))
let label: String = safe_str(node, "label")
let id: String = short_id(safe_str(node, "id"))
let report_section: String = report_section + int_to_str(i + 1) + ". [" + id + "] " + label + "\n"
let i: Int = i + 1
}
return report + report_section
}
// Section: Top Salient Nodes
fn show_top_salient(limit: Int, report: String) -> String {
section_header("Top " + int_to_str(limit) + " by Salience")
let path: String = "/api/nodes?limit=" + int_to_str(limit) + "&min_salience=0.0"
let json_str: String = api_get(path)
if json_str == "" {
println(" " + color_dim("No nodes or server unreachable"))
return report
}
let nodes: List = json_parse(json_str)
let n: Int = list_len(nodes)
if n == 0 {
println(" " + color_dim("(no nodes)"))
return report
}
println(" " + color_dim("Salience ranking:"))
println("")
let report_section: String = "\n=== Top Salient Nodes ===\n"
let i: Int = 0
while i < n {
let node: String = json_stringify(list_get(nodes, i))
let id: String = short_id(safe_str(node, "id"))
let label: String = safe_str(node, "label")
let sal: Float = safe_float(node, "salience")
let tier: String = safe_str(node, "tier")
let bar: String = salience_bar(sal)
let rank: String = str_pad_left(int_to_str(i + 1), 2, " ")
println(" " + rank + ". " + bar + " " + format_float(sal, 3) + " " + color_dim(id) + " " + str_pad_right(label, 35, " ") + " " + color_dim(tier))
let report_section: String = report_section + rank + ". " + format_float(sal, 3) + " [" + id + "] " + label + " " + tier + "\n"
let i: Int = i + 1
}
return report + report_section
}
// Section: Node Detail
fn show_node_detail(node_id: String, report: String) -> String {
section_header("Node Detail — " + str_slice(node_id, 0, 8) + "...")
let path: String = "/api/nodes/" + node_id
let json_str: String = api_get(path)
if json_str == "" {
println(" " + color_red("Node not found: " + node_id))
return report
}
render_node_detail(json_str)
// Show neighbors
let nb_path: String = "/api/neighbors/" + node_id + "?depth=2"
let nb_json: String = api_get(nb_path)
if nb_json != "" {
let neighbors: List = json_parse(nb_json)
let nb_n: Int = list_len(neighbors)
if nb_n > 0 {
println("")
println(" " + color_bold("Neighbors (" + int_to_str(nb_n) + "):"))
let j: Int = 0
while j < nb_n {
let nb: String = json_stringify(list_get(neighbors, j))
// Use json_get_raw to extract nested objects as JSON strings
let nb_node: String = json_get_raw(nb, "node")
let nb_edge: String = json_get_raw(nb, "edge")
let hops: Int = safe_int(nb, "hops")
let nb_label: String = safe_str(nb_node, "label")
let nb_id: String = short_id(safe_str(nb_node, "id"))
let hop_str: String = str_pad_left(int_to_str(hops), 2, " ")
let relation: String = safe_str(nb_edge, "relation")
println(" hop " + hop_str + " " + color_dim(nb_id) + " " + color_cyan(relation) + "" + nb_label)
let j: Int = j + 1
}
}
}
return report + "\n=== Node Detail: " + node_id + " ===\n" + "Fetched node details\n"
}
// Section: Search
fn show_search(query: String, limit: Int, report: String) -> String {
section_header("Search: \"" + query + "\"")
let path: String = "/api/search?q=" + query + "&limit=" + int_to_str(limit)
let json_str: String = api_get(path)
if json_str == "" {
println(" " + color_dim("No results or server unreachable"))
return report
}
let nodes: List = json_parse(json_str)
let n: Int = list_len(nodes)
println(" " + color_bold("Found " + int_to_str(n) + " results:"))
println("")
if n == 0 {
println(" " + color_dim("(no matches)"))
return report + "\n=== Search: " + query + " ===\nNo results\n"
}
let report_section: String = "\n=== Search: " + query + " ===\n" + int_to_str(n) + " results:\n"
let i: Int = 0
while i < n {
let node: String = json_stringify(list_get(nodes, i))
println(render_node_row(node, i))
let label: String = safe_str(node, "label")
let report_section: String = report_section + int_to_str(i + 1) + ". " + label + "\n"
let i: Int = i + 1
}
return report + report_section
}
// Section: Tier Browser
fn show_nodes_by_tier(tier: String, limit: Int, report: String) -> String {
let title: String = "Nodes — tier: " + tier
section_header(title)
let path: String = "/api/nodes?tier=" + tier + "&limit=" + int_to_str(limit)
let json_str: String = api_get(path)
if json_str == "" {
println(" " + color_dim("No nodes or server unreachable"))
return report
}
let nodes: List = json_parse(json_str)
let n: Int = list_len(nodes)
if n == 0 {
println(" " + color_dim("(no " + tier + " tier nodes)"))
return report
}
println(" " + tier_badge(tier) + " " + color_dim("Showing " + int_to_str(n) + " nodes"))
println("")
let i: Int = 0
let report_section: String = "\n=== " + tier + " Tier Nodes ===\n"
while i < n {
let node: String = json_stringify(list_get(nodes, i))
println(render_node_row(node, i))
let label: String = safe_str(node, "label")
let id: String = short_id(safe_str(node, "id"))
let report_section: String = report_section + "[" + id + "] " + label + "\n"
let i: Int = i + 1
}
return report + report_section
}
// Section: Spreading Activation
fn show_activation(seed_id: String, limit: Int, report: String) -> String {
section_header("Spreading Activation — seed: " + str_slice(seed_id, 0, 8) + "...")
let path: String = "/api/activate?seeds=" + seed_id + "&limit=" + int_to_str(limit) + "&depth=3"
let json_str: String = api_get(path)
if json_str == "" {
println(" " + color_dim("No activation results or server unreachable"))
return report
}
// Use json_get_raw to get the "results" array as a JSON string, then parse it
let results_raw: String = json_get_raw(json_str, "results")
let results: List = json_parse(results_raw)
let n: Int = list_len(results)
if n == 0 {
println(" " + color_dim("(no spreading activation results — check seed ID)"))
return report
}
println(" " + color_bold("Activated " + int_to_str(n) + " nodes:"))
println("")
let header: String = " " + str_pad_right(" # ID Label", 52, " ") + " Strength Hops"
println(color_dim(header))
println(color_dim(" " + repeat_str("", 68)))
let report_section: String = "\n=== Activation from " + str_slice(seed_id, 0, 8) + " ===\n"
let i: Int = 0
while i < n {
let result: String = json_stringify(list_get(results, i))
// Use json_get_raw to extract nested node object as a JSON string
let node: String = json_get_raw(result, "node")
let strength: Float = safe_float(result, "activation_strength")
let hops: Int = safe_int(result, "hops")
let id: String = short_id(safe_str(node, "id"))
let label: String = safe_str(node, "label")
let rank: String = str_pad_left(int_to_str(i + 1), 3, " ")
let strength_bar: String = salience_bar(strength)
println(" " + rank + ". " + color_dim(id) + " " + str_pad_right(label, 36, " ") + " " + format_float(strength, 3) + " " + color_dim("hops:" + int_to_str(hops)))
let report_section: String = report_section + rank + ". [" + id + "] " + label + " strength=" + format_float(strength, 3) + " hops=" + int_to_str(hops) + "\n"
let i: Int = i + 1
}
return report + report_section
}
// Section: Edge Statistics
fn show_edges(limit: Int, report: String) -> String {
section_header("Edge Explorer (sample of " + int_to_str(limit) + ")")
let path: String = "/api/edges?limit=" + int_to_str(limit)
let json_str: String = api_get(path)
if json_str == "" {
println(" " + color_dim("No edges or server unreachable"))
return report
}
let edges: List = json_parse(json_str)
let n: Int = list_len(edges)
if n == 0 {
println(" " + color_dim("(no edges in database)"))
return report
}
println(" " + color_dim("Showing " + int_to_str(n) + " edges:"))
println("")
let header: String = " " + str_pad_right(" # From → To Relation", 56, " ") + " Weight"
println(color_dim(header))
println(color_dim(" " + repeat_str("", 68)))
let report_section: String = "\n=== Edges ===\n"
let i: Int = 0
while i < n {
let edge: String = json_stringify(list_get(edges, i))
let from_id: String = short_id(safe_str(edge, "from_id"))
let to_id: String = short_id(safe_str(edge, "to_id"))
let relation: String = safe_str(edge, "relation")
let weight: Float = safe_float(edge, "weight")
let rank: String = str_pad_left(int_to_str(i + 1), 3, " ")
println(" " + rank + ". " + color_dim(from_id) + " " + color_cyan("") + " " + color_dim(to_id) + " " + color_green(str_pad_right(relation, 20, " ")) + " " + format_float(weight, 3))
let report_section: String = report_section + from_id + " -[" + relation + "]-> " + to_id + " w=" + format_float(weight, 3) + "\n"
let i: Int = i + 1
}
return report + report_section
}
// Section: Knowledge Browser (Concept nodes grouped by tag prefix)
fn show_knowledge_browser(report: String) -> String {
section_header("Knowledge Browser — Concept Nodes")
let path: String = "/api/nodes?node_type=Concept&limit=50"
let json_str: String = api_get(path)
if json_str == "" {
println(" " + color_dim("No concept nodes or server unreachable"))
return report
}
let nodes: List = json_parse(json_str)
let n: Int = list_len(nodes)
if n == 0 {
println(" " + color_dim("(no Concept nodes — these are your domain knowledge anchors)"))
return report
}
println(" " + color_bold(int_to_str(n) + " concept nodes found:"))
println("")
let report_section: String = "\n=== Knowledge Browser ===\n"
let i: Int = 0
while i < n {
let node: String = json_stringify(list_get(nodes, i))
let id: String = short_id(safe_str(node, "id"))
let label: String = safe_str(node, "label")
let tier: String = safe_str(node, "tier")
let sal: Float = safe_float(node, "salience")
println(" " + color_green("") + " " + str_pad_right(label, 40, " ") + " " + color_dim(id) + " " + color_dim(tier) + " " + format_float(sal, 3))
let report_section: String = report_section + "" + label + " [" + id + "] " + tier + "\n"
let i: Int = i + 1
}
return report + report_section
}
// Section: Mode Simulation (interactive mode preview)
fn show_mode_menu() -> String {
let _ = section_header("Interactive Mode Preview")
println(" " + color_bold("Available commands (when running interactively):"))
println("")
println(" " + color_cyan("stats") + " — show database statistics")
println(" " + color_cyan("browse <type>") + " — browse nodes by type")
println(" types: Memory, Concept, Event, Entity, Process, InternalState")
println(" " + color_cyan("tier <tier>") + " — browse nodes by tier")
println(" tiers: Working, Episodic, Semantic, Procedural")
println(" " + color_cyan("search <query>") + " — full-text search")
println(" " + color_cyan("node <id>") + " — show node detail + neighbors")
println(" " + color_cyan("activate <id>") + " — spreading activation from seed")
println(" " + color_cyan("edges") + " — browse edges")
println(" " + color_cyan("top") + " — top nodes by salience")
println(" " + color_cyan("export <path>") + " — save text report to file")
println(" " + color_cyan("help") + " — show this menu")
println(" " + color_cyan("quit") + " — exit studio")
println("")
println(" " + color_dim("Tip: set ENGRAM_URL=http://host:port to connect to a different server"))
return ""
}
// Export report
fn export_report(content: String, path: String) -> String {
let _ = section_header("Report Export")
let header: String = "ENGRAM DATA STUDIO — Report\n"
+ "Generated: " + time_format(time_now_utc(), "ISO") + "\n"
+ "Server: " + get_base_url() + "\n"
+ repeat_str("=", 60) + "\n"
let ok: Bool = fs_write(path, header + content)
if ok {
println(" " + color_green("") + " Report saved to: " + color_bold(path))
println(" " + color_dim("Size: " + format_bytes(str_len(header + content))))
} else {
println(" " + color_red("") + " Failed to write report to: " + path)
}
return ""
}
// Connectivity check
fn check_connection() -> Bool {
let resp: String = api_get("/api/stats")
return resp != ""
}
//
// MAIN STUDIO ENTRY POINT
//
let base_url: String = get_base_url()
let WIDTH: Int = 64
// Banner
println("")
println(color_bold(double_top(WIDTH)))
println(color_bold(double_row(" ███████╗███╗ ██╗ ██████╗ ██████╗ █████╗ ███╗ ███╗", WIDTH)))
println(color_bold(double_row(" ██╔════╝████╗ ██║██╔════╝ ██╔══██╗██╔══██╗████╗ ████║", WIDTH)))
println(color_bold(double_row(" █████╗ ██╔██╗ ██║██║ ███╗██████╔╝███████║██╔████╔██║", WIDTH)))
println(color_bold(double_row(" ██╔══╝ ██║╚██╗██║██║ ██║██╔══██╗██╔══██║██║╚██╔╝██║", WIDTH)))
println(color_bold(double_row(" ███████╗██║ ╚████║╚██████╔╝██║ ██║██║ ██║██║ ╚═╝ ██║", WIDTH)))
println(color_bold(double_row(" ╚══════╝╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝", WIDTH)))
println(color_bold(double_row("", WIDTH)))
println(color_bold(double_row(" DATA STUDIO — Native El Application", WIDTH)))
println(color_bold(double_row("", WIDTH)))
println(color_bold(double_bot(WIDTH)))
println("")
println(" " + color_bold("Server: ") + color_cyan(base_url))
println(" " + color_bold("Version: ") + color_dim("El-native · 10-loop pass"))
println("")
// Connection check
let connected: Bool = check_connection()
if connected {
println(" " + color_green("") + " " + color_bold("Connection established"))
} else {
println(" " + color_red("") + " " + color_bold("Server unreachable"))
println(" " + color_dim("Start the server: ENGRAM_BIND=0.0.0.0:8340 engram-server --data-dir <path>"))
println(" " + color_dim("Or set ENGRAM_URL environment variable"))
println("")
println(" " + color_yellow("Continuing in offline mode — all sections will show placeholders"))
}
// Run all dashboard sections
let report: String = ""
// Section 1: Stats
let report: String = show_stats(report)
// Section 2: Recent nodes
let report: String = show_recent(20, report)
// Section 3: Top salient
let report: String = show_top_salient(10, report)
// Section 4: By node type Memory
let report: String = show_nodes("Memory", 10, report)
// Section 5: By node type Concept
let report: String = show_nodes("Concept", 10, report)
// Section 6: By node type Event
let report: String = show_nodes("Event", 8, report)
// Section 7: By node type Entity
let report: String = show_nodes("Entity", 8, report)
// Section 8: By node type Process
let report: String = show_nodes("Process", 8, report)
// Section 9: Tier Semantic
let report: String = show_nodes_by_tier("Semantic", 10, report)
// Section 10: Tier Episodic
let report: String = show_nodes_by_tier("Episodic", 10, report)
// Section 11: Knowledge browser (Concept nodes)
let report: String = show_knowledge_browser(report)
// Section 12: Text search samples
let report: String = show_search("memory", 10, report)
let report: String = show_search("concept", 8, report)
// Section 13: Edge explorer
let report: String = show_edges(15, report)
// Section 14: Interactive mode preview
show_mode_menu()
// Export report
let report_path: String = get_report_path()
export_report(report, report_path)
// Footer
println("")
println(color_bold(" " + repeat_str("", 60)))
println(" " + color_bold("Engram Data Studio") + color_dim(" — session complete"))
println(" " + color_dim(time_format(time_now_utc(), "ISO")))
println(color_bold(" " + repeat_str("", 60)))
println("")
+243
View File
@@ -0,0 +1,243 @@
// field_test.el Proof of concept: Hebbian field model
//
// Tests the core mechanics:
// 1. Nodes with 2D semantic positions and temporal coordinates
// 2. Edges with weights that grow via co-activation (Hebb's rule)
// 3. Spreading activation with path strength
// 4. Temporal decay in path strength
// 5. Epistemic confidence = node confidence * path strength
//
// No storage pure in-memory demonstration using print output.
// Math helpers
fn clamp_f(v: Float, lo: Float, hi: Float) -> Float {
if v < lo {
return lo
}
if v > hi {
return hi
}
return v
}
// L2 distance squared no sqrt needed for proximity comparison
fn dist_sq(ax: Float, ay: Float, bx: Float, by: Float) -> Float {
let dx: Float = ax - bx
let dy: Float = ay - by
return dx * dx + dy * dy
}
// Proximity score: 1 / (1 + dist_sq) range (0, 1], closer = higher
fn proximity(ax: Float, ay: Float, bx: Float, by: Float) -> Float {
let d: Float = dist_sq(ax, ay, bx, by)
return 1.0 / (1.0 + d)
}
// Linear temporal decay: 1.0 at t=0, decaying toward 0
// decay_rate: fraction lost per time unit
fn temporal_decay(age: Float, decay_rate: Float) -> Float {
let d: Float = 1.0 - decay_rate * age
return clamp_f(d, 0.0, 1.0)
}
// Hebbian learning
// New edge weight after co-activation event
// w_new = clamp(w + lr * a_i * a_j, 0, 1)
fn hebbian_update(weight: Float, act_i: Float, act_j: Float, lr: Float) -> Float {
let delta: Float = lr * act_i * act_j
return clamp_f(weight + delta, 0.0, 1.0)
}
// Edge decay between activations
// w_new = w * (1 - decay_rate)
fn edge_decay(weight: Float, decay_rate: Float) -> Float {
return clamp_f(weight * (1.0 - decay_rate), 0.0, 1.0)
}
// Path strength
// Path strength = edge_weight * temporal_decay(node_age)
// This is the confidence qualifier on a retrieval result
fn path_strength(edge_weight: Float, node_age: Float, decay_rate: Float) -> Float {
let td: Float = temporal_decay(node_age, decay_rate)
return edge_weight * td
}
// Epistemic confidence = node_confidence * path_strength
fn epistemic_confidence(node_confidence: Float, ps: Float) -> Float {
return node_confidence * ps
}
// Simulation
fn run_test() -> String {
println("=== Engram Field Model — Proof of Concept ===")
println("")
// Nodes
// Each node: id, label, semantic position (x, y), temporal coordinate, confidence
// Semantic space: 2D for demonstration
// x=0..1: concreteabstract
// y=0..1: negativepositive valence
println("── Nodes ──────────────────────────────────────")
println("A: 'patient has fever' pos=(0.2, 0.4) t=100")
println("B: 'influenza' pos=(0.3, 0.5) t=90")
println("C: 'drug interaction warning' pos=(0.6, 0.3) t=10 (old, unactivated)")
println("D: 'ibuprofen' pos=(0.65, 0.3) t=10 (old, unactivated)")
println("")
// Semantic positions
let ax: Float = 0.2
let ay: Float = 0.4
let bx: Float = 0.3
let by: Float = 0.5
let cx: Float = 0.6
let cy: Float = 0.3
let dx_pos: Float = 0.65
let dy_pos: Float = 0.3
// Initial proximity (latent gradient implicit from positions)
let prox_ab: Float = proximity(ax, ay, bx, by)
let prox_ac: Float = proximity(ax, ay, cx, cy)
let prox_cd: Float = proximity(cx, cy, dx_pos, dy_pos)
println("── Initial latent gradients (proximity) ───────")
println("A↔B proximity: " + float_to_str(prox_ab) + " (semantically close — fever/flu)")
println("A↔C proximity: " + float_to_str(prox_ac) + " (semantically distant)")
println("C↔D proximity: " + float_to_str(prox_cd) + " (close — drug interaction/ibuprofen)")
println("")
// Initial edge weights (all start near zero no co-activation yet)
let w_ab: Float = 0.0
let w_ac: Float = 0.0
let w_cd: Float = 0.0
println("── Initial edge weights ────────────────────────")
println("A→B: " + float_to_str(w_ab) + " (no co-activation yet)")
println("A→C: " + float_to_str(w_ac))
println("C→D: " + float_to_str(w_cd))
println("")
// Co-activation events
// The doctor CGI processes a patient with fever.
// A (fever) and B (influenza) co-activate the diagnosis fires both.
// Learning rate: 0.3
let lr: Float = 0.3
let act_strength: Float = 1.0 // full activation
println("── Co-activation event 1: patient with fever → flu diagnosis ──")
let w_ab_1: Float = hebbian_update(w_ab, act_strength, act_strength, lr)
println("A and B fire together (strength=1.0)")
println("A→B weight: " + float_to_str(w_ab) + "" + float_to_str(w_ab_1))
println("")
println("── Co-activation event 2: another flu case ──")
let w_ab_2: Float = hebbian_update(w_ab_1, act_strength, act_strength, lr)
println("A and B fire together again")
println("A→B weight: " + float_to_str(w_ab_1) + "" + float_to_str(w_ab_2))
println("")
println("── Co-activation event 3: third flu case ──")
let w_ab_3: Float = hebbian_update(w_ab_2, act_strength, act_strength, lr)
println("A and B fire together again")
println("A→B weight: " + float_to_str(w_ab_2) + "" + float_to_str(w_ab_3))
println("")
// C and D have never been activated in this context weights stay near zero
// (In practice, proximity means a latent gradient exists, but no learned edge yet)
// Query: activate A (fever), what spreads?
println("── Query: activate A (fever) ───────────────────")
println("Spreading activation from A...")
println("")
// Decay rates
let temporal_decay_rate: Float = 0.005 // per time unit
let current_t: Int = 200
// Node ages (current_t - node_t)
let age_b: Float = 110.0 // t=90, current=200
let age_c: Float = 190.0 // t=10, current=200
let age_d: Float = 190.0 // t=10, current=200
// Path strength to B: strong edge, recently relevant
let ps_b: Float = path_strength(w_ab_3, age_b, temporal_decay_rate)
let conf_b: Float = epistemic_confidence(0.9, ps_b)
// Path strength to C: no learned edge only latent proximity gradient
// Spreading activation from A can weakly reach C via proximity alone
let latent_ac: Float = prox_ac * 0.1 // proximity contributes small initial signal
let ps_c: Float = path_strength(latent_ac, age_c, temporal_decay_rate)
let conf_c: Float = epistemic_confidence(0.9, ps_c)
// Path strength to D via C: chain of weak signals
let ps_d: Float = path_strength(latent_ac * prox_cd * 0.1, age_d, temporal_decay_rate)
let conf_d: Float = epistemic_confidence(0.9, ps_d)
println("Result: B (influenza)")
println(" Edge weight: " + float_to_str(w_ab_3))
println(" Node age: " + float_to_str(age_b) + " time units")
println(" Temporal decay: " + float_to_str(temporal_decay(age_b, temporal_decay_rate)))
println(" Path strength: " + float_to_str(ps_b))
println(" Confidence: " + float_to_str(conf_b))
println(" → STRONG: B surfaces with high confidence")
println("")
println("Result: C (drug interaction warning)")
println(" Edge weight: " + float_to_str(latent_ac) + " (latent only — never co-activated)")
println(" Node age: " + float_to_str(age_c) + " time units")
println(" Temporal decay: " + float_to_str(temporal_decay(age_c, temporal_decay_rate)))
println(" Path strength: " + float_to_str(ps_c))
println(" Confidence: " + float_to_str(conf_c))
println(" → WEAK: C is distant and old — attenuated path triggers refresh signal")
println("")
println("Result: D (ibuprofen) via C")
println(" Path strength: " + float_to_str(ps_d))
println(" Confidence: " + float_to_str(conf_d))
println(" → VERY WEAK: chain of attenuated edges")
println("")
// Refresh trigger
println("── Attenuation trigger ─────────────────────────")
let threshold: Float = 0.2
println("Confidence threshold: " + float_to_str(threshold))
if conf_c < threshold {
println("C is below threshold (" + float_to_str(conf_c) + " < " + float_to_str(threshold) + ")")
println("→ Trigger: 'drug interaction warning node found but path is weak.")
println(" Last activated " + float_to_str(age_c) + " time units ago.")
println(" Recommend fetching current information before acting.'")
}
println("")
// After refresh: C and D co-activate with A
println("── Refresh: doctor looks up drug interactions ──")
println("A, C, D all co-activate during research")
let w_ac_new: Float = hebbian_update(0.0, act_strength, act_strength, lr)
let w_cd_new: Float = hebbian_update(0.0, act_strength, act_strength, lr)
let age_c_new: Float = 0.0 // just activated
let age_d_new: Float = 0.0
let ps_c_new: Float = path_strength(w_ac_new, age_c_new, temporal_decay_rate)
let conf_c_new: Float = epistemic_confidence(0.9, ps_c_new)
println("A→C weight after refresh: " + float_to_str(w_ac_new))
println("C→D weight after refresh: " + float_to_str(w_cd_new))
println("C confidence after refresh: " + float_to_str(conf_c_new))
println("→ Edges strengthened. Drug interaction now reachable with high confidence.")
println("")
println("=== Result ===")
println("Perfect memory: all nodes present throughout.")
println("Calibrated confidence: B (flu) high, C/D (drug interaction) low until refreshed.")
println("Self-correcting: attenuation triggered fetch, fetch strengthened edges.")
println("The field works.")
return "ok"
}
let result: String = run_test()
+103
View File
@@ -0,0 +1,103 @@
// language_features_test.el tests for new operators and builtins
// 1. Modulo operator
let m = 17 % 5
println(int_to_str(m))
// 2. Bitwise ops
let flags_and = 10 & 12
let flags_xor = 10 ^ 12
let flags_shl = 1 << 3
let flags_shr = 16 >> 2
println(int_to_str(flags_and))
println(int_to_str(flags_xor))
println(int_to_str(flags_shl))
println(int_to_str(flags_shr))
// 3. Math trig
let sin0 = math_sin(0.0)
let cos0 = math_cos(0.0)
let pi_val = math_pi()
println(float_to_str(sin0))
println(float_to_str(cos0))
println(float_to_str(pi_val))
// 4. String padding
let padded = str_pad_left("42", 5, "0")
println(padded)
let padded_r = str_pad_right("hi", 5, ".")
println(padded_r)
// 5. str_format
let tmpl = "Hello {name}, you are {age} years old!"
let data = {"name": "Will", "age": "30"}
let formatted = str_format(tmpl, data)
println(formatted)
// 6. format_float
let ff = format_float(3.14159, 2)
println(ff)
// 7. Time
let ts = time_now_utc()
let parts = time_to_parts(ts)
let iso_str = time_format(ts, "ISO")
println(iso_str)
// 8. Time add/diff
let ts2 = time_add(ts, 7, "day")
let diff = time_diff(ts, ts2, "day")
println(int_to_str(diff))
// 9. List range
let rng = list_range(0, 5)
println(list_join(rng, ","))
// 10. Stack push/pop
let s0 = stack_new()
let s1 = stack_push(s0, 10)
let s2 = stack_push(s1, 20)
let top = stack_peek(s2)
let s3 = stack_pop(s2)
println(int_to_str(top))
// 11. Queue enqueue/dequeue
let q0 = queue_new()
let q1 = queue_enqueue(q0, "first")
let q2 = queue_enqueue(q1, "second")
let front = queue_peek(q2)
let q3 = queue_dequeue(q2)
println(front)
// 12. Decimal round
let rounded = decimal_round(3.14159, 2)
println(float_to_str(rounded))
// 13. int_to_float / float_to_int
let fi = int_to_float(42)
let if_ = float_to_int(3.9)
println(float_to_str(fi))
println(int_to_str(if_))
// 14. is_nil / unwrap_or
let n = unwrap_or(is_nil(42), false)
println(bool_to_str(n))
// 15. list_push, list_pop, list_range
let lst = list_new()
let lst2 = list_push(lst, 100)
let lst3 = list_push(lst2, 200)
let last_elem = list_peek_last(lst3)
println(int_to_str(last_elem))
// 16. Char ops
let char_a = str_char_at("hello", 1)
let code_e = str_char_code("hello", 1)
let ch_from = str_from_char_code(65)
println(char_a)
println(int_to_str(code_e))
println(ch_from)
// Done
println("all tests complete")
+10
View File
@@ -0,0 +1,10 @@
// Test LLM native functions (with ANTHROPIC_API_KEY in env)
let models: List = llm_models()
println("Available models: " + int_to_str(list_len(models)))
// This test skips actual API calls since they need env vars
// Just verify the functions exist and don't crash on missing keys
let missing_key_result: String = llm_call("claude", "ping")
println("llm_call returned (may be error without API key): " + str_slice(missing_key_result, 0, 50))
println("LLM function registration: OK")