Archived
951b8d574b
Batches 2/3/4 of the runtime extension. The runtime grew from 1620
to 3112 lines (.c) and 247 to 286 lines (.h) — adding 27 new or
real-implementation builtins and replacing every batch-1 stub.
Batch 2 — HTTP / fs (8 builtins)
- http_get, http_post: replaced stubs with real libcurl client.
Network errors return JSON {"error":"..."} so callers can detect.
- http_post_json: sets Content-Type: application/json.
- http_get_with_headers, http_post_with_headers: ElMap → headers.
- http_post_form_auth: form-urlencoded + Authorization header
(Stripe-style API calls).
- http_serve: replaced stub with real POSIX-socket server, threaded,
capped at 64 concurrent connections. Auto-detects content type
(HTML / JSON / plain). Handler dispatch via named registry.
- fs_list: directory listing via opendir/readdir.
Batch 3 — In-process graph store (14 builtins)
- engram_node, engram_node_full: create node, returns UUID.
- engram_get_node, engram_forget, engram_node_count.
- engram_strengthen: Hebbian potentiation (+0.05, clamp 1.0,
bumps last_activated).
- engram_search, engram_scan_nodes: text search, paginated scan.
- engram_connect, engram_edge_between, engram_neighbors,
engram_neighbors_filtered, engram_edge_count.
- engram_activate: real spreading-activation algorithm.
BFS to depth, max-activation merge across paths, decay 0.7/hop,
multiplied by node confidence, filtered by epistemic_confidence
≥ 0.2 (refresh threshold), sorted desc.
- engram_save, engram_load: JSON snapshot persistence.
Batch 4 — LLM (5 builtins)
- llm_call, llm_call_system: Anthropic /v1/messages via libcurl.
ANTHROPIC_API_KEY from env. Default model claude-sonnet-4-5.
- llm_vision: adds image content block. URL / base64 / file path
detected by prefix.
- llm_models: returns the available model list.
- llm_call_agentic: stubbed with TODO (single-turn fallback to
llm_call_system); full tool_use loop is the next iteration.
Codegen fix: emit Float literals as `el_from_float(<v>)`. Without
the wrapper, C implicit conversion truncates 0.8 to 0 when passed to
a builtin expecting el_val_t. Float helpers moved to el_runtime.h
so generated programs can call them.
Compile-time
- cc -std=c11 -Wall -Wextra -c el_runtime.c → no errors, no warnings.
- Link requires -lcurl -lpthread (documented in header comment).
Verified end-to-end
- engram_node × 2, engram_connect, engram_activate("Hebbian", 2)
returns 2 activated nodes with correct epistemic confidence.
- http_get("https://httpbin.org/get") returns 259-byte JSON live.
- Self-host closure: stage1 vs stage2 byte-identical against the
new runtime.
- engram_save → engram_load round-trip preserves graph.
dist/platform/elc rebuilt against the new runtime (147 KB, up from
94 KB due to libcurl link). .prev2 preserves the prior binary.
303 lines
15 KiB
C
303 lines
15 KiB
C
/*
|
|
* 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).
|
|
*
|
|
* Canonical compile command:
|
|
* cc -std=c11 -I el-compiler/runtime -lcurl -lpthread \
|
|
* -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);
|
|
|
|
/* ── 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);
|
|
|
|
/* ── 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);
|
|
void http_serve(el_val_t port, el_val_t handler);
|
|
void http_set_handler(el_val_t name);
|
|
|
|
/* ── 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);
|
|
|
|
/* ── 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);
|
|
|
|
/* ── Time ────────────────────────────────────────────────────────────────── */
|
|
|
|
el_val_t time_now(void);
|
|
el_val_t time_now_utc(void);
|
|
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);
|
|
|
|
/* ── 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 template, el_val_t data);
|
|
el_val_t str_lower(el_val_t s);
|
|
el_val_t str_upper(el_val_t s);
|
|
|
|
/* ── 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);
|
|
|
|
/* ── Process ─────────────────────────────────────────────────────────────── */
|
|
|
|
void exit_program(el_val_t code);
|
|
|
|
/* ── 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).
|
|
* Stubs print descriptive output and return empty/zero values.
|
|
* Full implementations are linked from the DHARMA runtime at deploy time. */
|
|
|
|
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);
|
|
|
|
/* ── 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);
|
|
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_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);
|
|
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);
|
|
|
|
/* ── 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);
|
|
|
|
/* ── 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);
|
|
|
|
/* ── 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_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 */
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|