@@ -2229,9 +2229,11 @@ impl Interpreter {
22292229 | "sha256" | "sha512" | "base64_encode" | "base64_decode"
22302230 // LLM builtins
22312231 | "llm_call" | "llm_chat" | "llm_embed" | "llm_models" | "llm_system"
2232- | "llm_stream_print"
2232+ | "llm_stream_print" | "llm_judge" | "llm_compare"
22332233 | "llm_tools" | "substrate_embed"
22342234 | "batch_llm_call" | "batch_llm_chat"
2235+ // File utilities
2236+ | "file_ls"
22352237 // HTTP builtins
22362238 | "http_get" | "http_post" | "http_post_json" | "http_put" | "http_delete"
22372239 | "now_iso" | "now_unix" | "format_time" | "parse_time"
@@ -4867,6 +4869,22 @@ impl Interpreter {
48674869 let exists = std::path::Path::new(&path).exists();
48684870 Ok(Value::HInt(HInt::new(if exists { 1 } else { 0 })))
48694871 }
4872+ "file_ls" => {
4873+ let path = if args.is_empty() {
4874+ ".".to_string()
4875+ } else {
4876+ self.eval_expr(&args[0])?.to_display_string()
4877+ };
4878+ let entries = std::fs::read_dir(&path)
4879+ .map_err(|e| format!("file_ls: {}", e))?;
4880+ let mut names: Vec<Value> = Vec::new();
4881+ for entry in entries.flatten() {
4882+ let name = entry.file_name().to_string_lossy().to_string();
4883+ names.push(Value::String(name));
4884+ }
4885+ names.sort_by(|a, b| a.to_display_string().cmp(&b.to_display_string()));
4886+ Ok(Value::Array(HArray::from_vec(names)))
4887+ }
48704888 // Introspection and utility.
48714889 "type_of" => {
48724890 if args.is_empty() {
@@ -9601,6 +9619,39 @@ impl Interpreter {
96019619 };
96029620 crate::llm_builtins::llm_stream_print(&prompt, system.as_deref(), model.as_deref())
96039621 }
9622+ // llm_judge(responses, criteria, model?) -> dict[]
9623+ // Score each response in an array; returns [{idx, score, reason}] sorted best-first.
9624+ "llm_judge" => {
9625+ if args.len() < 2 {
9626+ return Err("llm_judge requires (responses, criteria, model?)".to_string());
9627+ }
9628+ let responses = self.eval_expr(&args[0])?;
9629+ let criteria = self.eval_expr(&args[1])?.to_display_string();
9630+ let model = if args.len() > 2 {
9631+ match self.eval_expr(&args[2])? {
9632+ Value::Null => None,
9633+ v => Some(v.to_display_string()),
9634+ }
9635+ } else { None };
9636+ crate::llm_builtins::llm_judge(&responses, &criteria, model.as_deref())
9637+ }
9638+ // llm_compare(a, b, criteria, model?) -> dict
9639+ // Pick the better of two responses; returns {winner: "A"|"B", reason: "..."}.
9640+ "llm_compare" => {
9641+ if args.len() < 3 {
9642+ return Err("llm_compare requires (a, b, criteria, model?)".to_string());
9643+ }
9644+ let a = self.eval_expr(&args[0])?.to_display_string();
9645+ let b = self.eval_expr(&args[1])?.to_display_string();
9646+ let criteria = self.eval_expr(&args[2])?.to_display_string();
9647+ let model = if args.len() > 3 {
9648+ match self.eval_expr(&args[3])? {
9649+ Value::Null => None,
9650+ v => Some(v.to_display_string()),
9651+ }
9652+ } else { None };
9653+ crate::llm_builtins::llm_compare(&a, &b, &criteria, model.as_deref())
9654+ }
96049655 // llm_models() -> dict[]
96059656 // Returns the list of models available from the active provider.
96069657 // Each element is a dict with at least {"id": string, "provider": string}.
@@ -14555,8 +14606,10 @@ pub(crate) const HEAL_BUILTIN_NAMES: &[&str] = &[
1455514606 "re_match", "re_find", "re_find_all", "re_replace", "re_split",
1455614607 "json_parse", "json_stringify", "json_extract", "str_format",
1455714608 "sha256", "sha512", "base64_encode", "base64_decode",
14558- // LLM builtins (Anthropic API — enabled with llm-builtins feature)
14559- "llm_call", "llm_chat", "llm_embed",
14609+ // LLM builtins
14610+ "llm_call", "llm_chat", "llm_embed", "llm_models", "llm_system",
14611+ "llm_stream_print", "llm_judge", "llm_compare",
14612+ "llm_tools", "substrate_embed",
1456014613 "batch_llm_call", "batch_llm_chat",
1456114614 // Native HTTP builtins
1456214615 "http_get", "http_post", "http_post_json", "http_put", "http_delete",
@@ -14633,7 +14686,7 @@ pub(crate) const HEAL_BUILTIN_NAMES: &[&str] = &[
1463314686 "is_singularity", "ensure_clean", "collapse", "invert",
1463414687 "quantize", "quantization_ratio",
1463514688 // I/O
14636- "read_file", "write_file", "file_exists", "print",
14689+ "read_file", "write_file", "file_exists", "file_ls", " print",
1463714690 "println", "print_raw",
1463814691 // Time / random / conversion / introspection
1463914692 "now_ms", "random_int", "random_float", "random_seed",
0 commit comments