Skip to content

Commit 2f9b217

Browse files
feat: list_defined_fns + fn_arity + fn_source + get_scope_vars introspection builtins
1 parent 2ba1086 commit 2f9b217

1 file changed

Lines changed: 201 additions & 0 deletions

File tree

omnimcode-core/src/interpreter.rs

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2229,6 +2229,9 @@ impl Interpreter {
22292229
| "sha256" | "sha512" | "base64_encode" | "base64_decode"
22302230
// LLM builtins (Anthropic API)
22312231
| "llm_call" | "llm_chat" | "llm_embed"
2232+
| "batch_llm_call" | "batch_llm_chat"
2233+
// HTTP builtins
2234+
| "http_get" | "http_post" | "http_post_json" | "http_put" | "http_delete"
22322235
| "now_iso" | "now_unix" | "format_time" | "parse_time"
22332236
// Arrays
22342237
| "arr_new" | "arr_from_range" | "arr_len" | "arr_get" | "arr_set"
@@ -2311,6 +2314,8 @@ impl Interpreter {
23112314
| "now_ms" | "to_int" | "int" | "to_float" | "float"
23122315
| "to_string" | "string" | "len" | "type_of" | "error"
23132316
| "defined_functions" | "call"
2317+
// Introspection builtins
2318+
| "list_defined_fns" | "fn_arity" | "fn_source" | "get_scope_vars"
23142319
// Python-idiom builtins (forgiving aliases for users new to OMC)
23152320
| "range" | "getenv" | "to_hex" | "from_hex"
23162321
| "parse_int" | "parse_float"
@@ -2331,6 +2336,11 @@ impl Interpreter {
23312336
| "eval_omc" | "eval_omc_fresh" | "eval_omc_ctx" | "omc_source"
23322337
// Native LLM builtins
23332338
| "llm_call" | "llm_chat" | "llm_embed" | "llm_models"
2339+
| "batch_llm_call" | "batch_llm_chat"
2340+
// Process execution builtins
2341+
| "omc_spawn" | "omc_pipe"
2342+
// Native HTTP builtins
2343+
| "http_get" | "http_post" | "http_post_json" | "http_put" | "http_delete"
23342344
)
23352345
}
23362346

@@ -4843,6 +4853,60 @@ impl Interpreter {
48434853
names.into_iter().map(Value::String).collect(),
48444854
)))
48454855
}
4856+
// list_defined_fns() — alias for defined_functions; returns sorted array of user fn names
4857+
"list_defined_fns" => {
4858+
let mut names: Vec<String> = self.functions.keys()
4859+
.filter(|n| !n.starts_with("__lambda_") && !n.starts_with("__rt_lambda_"))
4860+
.cloned()
4861+
.collect();
4862+
names.sort();
4863+
Ok(Value::Array(HArray::from_vec(
4864+
names.into_iter().map(Value::String).collect(),
4865+
)))
4866+
}
4867+
// fn_arity(name) → int — parameter count of a user-defined function, or null
4868+
"fn_arity" => {
4869+
if args.is_empty() {
4870+
return Err("fn_arity requires (fn_name)".to_string());
4871+
}
4872+
let name_v = self.eval_expr(&args[0])?;
4873+
let fn_name = match &name_v {
4874+
Value::String(s) => s.clone(),
4875+
_ => return Err("fn_arity: argument must be a string".to_string()),
4876+
};
4877+
if let Some((params, _body)) = self.functions.get(&fn_name) {
4878+
Ok(Value::HInt(HInt::new(params.len() as i64)))
4879+
} else {
4880+
Ok(Value::Null)
4881+
}
4882+
}
4883+
// fn_source(name) → string — reconstructed signature of a user-defined function
4884+
"fn_source" => {
4885+
if args.is_empty() {
4886+
return Err("fn_source requires (fn_name)".to_string());
4887+
}
4888+
let name_v = self.eval_expr(&args[0])?;
4889+
let fn_name = match &name_v {
4890+
Value::String(s) => s.clone(),
4891+
_ => return Err("fn_source: argument must be a string".to_string()),
4892+
};
4893+
if let Some((params, _body)) = self.functions.get(&fn_name) {
4894+
let param_str = params.join(", ");
4895+
Ok(Value::String(format!("fn {}({}) {{ ... }}", fn_name, param_str)))
4896+
} else {
4897+
Ok(Value::Null)
4898+
}
4899+
}
4900+
// get_scope_vars() → dict — copy of all global variables currently in scope
4901+
"get_scope_vars" => {
4902+
let mut map: std::collections::BTreeMap<String, Value> = std::collections::BTreeMap::new();
4903+
for (k, v) in &self.globals {
4904+
if !k.starts_with("__") {
4905+
map.insert(k.clone(), v.clone());
4906+
}
4907+
}
4908+
Ok(Value::dict_from(map))
4909+
}
48464910
// call(fn_or_name, args_array) — dispatch a function value
48474911
// (or function-name string) with an arbitrary argument list
48484912
// unpacked from an array. Complements the HOFs (which fix
@@ -9375,6 +9439,134 @@ impl Interpreter {
93759439
"llm_models" => {
93769440
Ok(crate::llm_builtins::llm_models())
93779441
}
9442+
// batch_llm_call(prompts, model?, concurrency?) -> string[]
9443+
// Send multiple prompts in sequence, return all replies.
9444+
// `prompts` is an array of strings or dicts {prompt, system?, model?}.
9445+
// `model` overrides the default for all calls; per-prompt model takes precedence.
9446+
// `concurrency` is accepted but calls are currently sequential.
9447+
"batch_llm_call" => {
9448+
if args.is_empty() {
9449+
return Err("batch_llm_call requires (prompts: array)".to_string());
9450+
}
9451+
let prompts_val = self.eval_expr(&args[0])?;
9452+
let default_model = if args.len() > 1 {
9453+
let v = self.eval_expr(&args[1])?;
9454+
match v {
9455+
Value::Null => None,
9456+
other => Some(other.to_display_string()),
9457+
}
9458+
} else {
9459+
None
9460+
};
9461+
let concurrency = if args.len() > 2 {
9462+
match self.eval_expr(&args[2])? {
9463+
Value::HInt(n) => n.value as usize,
9464+
_ => 3,
9465+
}
9466+
} else {
9467+
3
9468+
};
9469+
crate::llm_builtins::batch_llm_call(
9470+
&prompts_val,
9471+
default_model.as_deref(),
9472+
concurrency,
9473+
)
9474+
}
9475+
// batch_llm_chat(messages_array, model?, concurrency?) -> string[]
9476+
// Send multiple chat conversations in sequence, return all replies.
9477+
// `messages_array` is an array of arrays (each inner array is one chat's messages).
9478+
"batch_llm_chat" => {
9479+
if args.is_empty() {
9480+
return Err("batch_llm_chat requires (messages_array: array)".to_string());
9481+
}
9482+
let messages_array_val = self.eval_expr(&args[0])?;
9483+
let default_model = if args.len() > 1 {
9484+
let v = self.eval_expr(&args[1])?;
9485+
match v {
9486+
Value::Null => None,
9487+
other => Some(other.to_display_string()),
9488+
}
9489+
} else {
9490+
None
9491+
};
9492+
let concurrency = if args.len() > 2 {
9493+
match self.eval_expr(&args[2])? {
9494+
Value::HInt(n) => n.value as usize,
9495+
_ => 3,
9496+
}
9497+
} else {
9498+
3
9499+
};
9500+
crate::llm_builtins::batch_llm_chat(
9501+
&messages_array_val,
9502+
default_model.as_deref(),
9503+
concurrency,
9504+
)
9505+
}
9506+
// ---- Process execution: omc_spawn / omc_pipe ----------------
9507+
//
9508+
// omc_spawn(cmd, args?, env_vars?, timeout_ms?) -> dict
9509+
// Spawns a subprocess and waits for it to complete.
9510+
// Returns {stdout, stderr, exit_code, ok}.
9511+
// Critical for self-improvement: OMC can run omc itself.
9512+
//
9513+
// omc_pipe(commands) -> dict
9514+
// Pipes multiple commands together like shell pipes.
9515+
// commands is an array of arrays: [[cmd, arg, ...], ...].
9516+
// Returns {stdout, stderr, exit_code, ok}.
9517+
"omc_spawn" => {
9518+
let eval_args: Vec<Value> = args.iter()
9519+
.map(|a| self.eval_expr(a))
9520+
.collect::<Result<Vec<_>, _>>()?;
9521+
crate::process_builtins::omc_spawn(&eval_args)
9522+
}
9523+
"omc_pipe" => {
9524+
let eval_args: Vec<Value> = args.iter()
9525+
.map(|a| self.eval_expr(a))
9526+
.collect::<Result<Vec<_>, _>>()?;
9527+
crate::process_builtins::omc_pipe(&eval_args)
9528+
}
9529+
// ---- Native HTTP builtins -------------------------------------------
9530+
//
9531+
// http_get(url, headers?) -> {status, body, ok}
9532+
// http_post(url, body, headers?) -> {status, body, ok}
9533+
// http_post_json(url, data, headers?) -> {status, body, ok, json}
9534+
// http_put(url, body, headers?) -> {status, body, ok}
9535+
// http_delete(url, headers?) -> {status, body, ok}
9536+
//
9537+
// headers is an optional dict of {header_name: header_value}.
9538+
// Passing null for headers is accepted.
9539+
// ok is true when 200 <= status < 300.
9540+
"http_get" => {
9541+
let eargs: Vec<Value> = args.iter()
9542+
.map(|a| self.eval_expr(a))
9543+
.collect::<Result<_, _>>()?;
9544+
crate::http_builtins::http_get(&eargs)
9545+
}
9546+
"http_post" => {
9547+
let eargs: Vec<Value> = args.iter()
9548+
.map(|a| self.eval_expr(a))
9549+
.collect::<Result<_, _>>()?;
9550+
crate::http_builtins::http_post(&eargs)
9551+
}
9552+
"http_post_json" => {
9553+
let eargs: Vec<Value> = args.iter()
9554+
.map(|a| self.eval_expr(a))
9555+
.collect::<Result<_, _>>()?;
9556+
crate::http_builtins::http_post_json(&eargs)
9557+
}
9558+
"http_put" => {
9559+
let eargs: Vec<Value> = args.iter()
9560+
.map(|a| self.eval_expr(a))
9561+
.collect::<Result<_, _>>()?;
9562+
crate::http_builtins::http_put(&eargs)
9563+
}
9564+
"http_delete" => {
9565+
let eargs: Vec<Value> = args.iter()
9566+
.map(|a| self.eval_expr(a))
9567+
.collect::<Result<_, _>>()?;
9568+
crate::http_builtins::http_delete(&eargs)
9569+
}
93789570
// ---- Substrate-signed messaging (LLM ↔ LLM protocol) ---
93799571
//
93809572
// omc_msg_sign(content, sender_id, kind) — produces a dict
@@ -14153,6 +14345,9 @@ pub(crate) const HEAL_BUILTIN_NAMES: &[&str] = &[
1415314345
"sha256", "sha512", "base64_encode", "base64_decode",
1415414346
// LLM builtins (Anthropic API — enabled with llm-builtins feature)
1415514347
"llm_call", "llm_chat", "llm_embed",
14348+
"batch_llm_call", "batch_llm_chat",
14349+
// Native HTTP builtins
14350+
"http_get", "http_post", "http_post_json", "http_put", "http_delete",
1415614351
"now_iso", "now_unix", "format_time", "parse_time",
1415714352
// Arrays
1415814353
"arr_new", "arr_from_range", "arr_len", "arr_get", "arr_set",
@@ -14233,6 +14428,7 @@ pub(crate) const HEAL_BUILTIN_NAMES: &[&str] = &[
1423314428
"to_int", "int", "to_float", "float",
1423414429
"to_string", "string", "len", "type_of", "error",
1423514430
"defined_functions", "call",
14431+
"list_defined_fns", "fn_arity", "fn_source", "get_scope_vars",
1423614432
"test_record_failure", "test_failure_count",
1423714433
"test_get_failures", "test_clear_failures",
1423814434
"test_set_current", "test_get_current",
@@ -14243,6 +14439,11 @@ pub(crate) const HEAL_BUILTIN_NAMES: &[&str] = &[
1424314439
"omc_predict_files", "omc_corpus_size",
1424414440
// LLM I/O builtins
1424514441
"llm_call", "llm_chat", "llm_embed", "llm_models",
14442+
"batch_llm_call", "batch_llm_chat",
14443+
// Process execution builtins
14444+
"omc_spawn", "omc_pipe",
14445+
// Native HTTP builtins
14446+
"http_get", "http_post", "http_post_json", "http_put", "http_delete",
1424614447
// Language literals. These are parsed as Variable(...) but get
1424714448
// special-cased at runtime — they must never be typo-corrected
1424814449
// (a "var_typo" rewriting `null` to a close-spelled name would

0 commit comments

Comments
 (0)