feat(soul): MCP connectors — /api/connectors proxy + per-connector auto-approve

Adds the soul side of the connectors feature (spec: docs/research/
mcp-connectors-adoption-spec.md). The soul thin-proxies the neuron-connectd
bridge on 127.0.0.1:7771 so the UI talks to one origin and never reaches the
bridge directly.

routes.el:
- handle_connectors + connectd_get/connectd_post helpers (POST bodies go via
  a temp file + curl -d @file, so model/UI input can't reach the shell).
- GET /api/connectors and POST /api/connectors/{add,toggle,auto-approve,
  remove,secret,oauth/start} registered in both GET and POST routers.

chat.el:
- tool_auto_approved(): an mcp__* tool skips the approval card only when its
  server is explicitly opted in (off by default; built-in tools unaffected;
  bridge down -> false). Wired into the agentic approval gate so an
  auto-approved connector tool flows straight to execution.

Regenerated dist/chat.c and dist/routes.c. Verified live on :7770: real chat,
recall, and /api/connectors all work after promotion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Tim Lingo
2026-06-13 18:43:14 -05:00
parent 8eea1d94ff
commit 6c57d4fe1b
4 changed files with 1079 additions and 314 deletions
Vendored
+378 -122
View File
@@ -31,8 +31,23 @@ el_val_t handle_see(el_val_t body);
el_val_t studio_tools_json(void);
el_val_t agentic_api_key(void);
el_val_t agentic_tools_literal(void);
el_val_t agentic_tools_with_web(void);
el_val_t str_begins(el_val_t s, el_val_t pre);
el_val_t connector_tools_json(void);
el_val_t agentic_tools_all(void);
el_val_t call_mcp_bridge(el_val_t tool_name, el_val_t tool_input);
el_val_t tool_auto_approved(el_val_t tool_name);
el_val_t dispatch_tool(el_val_t tool_name, el_val_t tool_input);
el_val_t json_array_append(el_val_t arr, el_val_t item);
el_val_t append_tool_log(el_val_t log, el_val_t name);
el_val_t exec_tool_block(el_val_t block);
el_val_t agentic_blob(el_val_t model, el_val_t system, el_val_t tools_json, el_val_t messages, el_val_t origin, el_val_t approval, el_val_t iteration, el_val_t tools_log, el_val_t content, el_val_t queue, el_val_t results, el_val_t next);
el_val_t extract_all_text(el_val_t s);
el_val_t strip_citations(el_val_t s);
el_val_t agentic_api_turn(el_val_t model, el_val_t safe_sys, el_val_t tools_json, el_val_t messages);
el_val_t agentic_engine(el_val_t session_id, el_val_t blob);
el_val_t handle_chat_agentic(el_val_t body);
el_val_t handle_session_approve(el_val_t session_id, el_val_t body);
el_val_t handle_chat_as_soul(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);
@@ -74,11 +89,7 @@ el_val_t engram_compile(el_val_t intent) {
}
el_val_t json_safe(el_val_t s) {
el_val_t s1 = str_replace(s, EL_STR("\\"), EL_STR("\\\\"));
el_val_t s2 = str_replace(s1, EL_STR("\""), EL_STR("\\\""));
el_val_t s3 = str_replace(s2, EL_STR("\n"), EL_STR("\\n"));
el_val_t s4 = str_replace(s3, EL_STR("\r"), EL_STR("\\r"));
return s4;
return json_escape_string(s);
return 0;
}
@@ -231,6 +242,72 @@ el_val_t agentic_tools_literal(void) {
return 0;
}
el_val_t agentic_tools_with_web(void) {
el_val_t base = agentic_tools_literal();
el_val_t inner = str_slice(base, 1, (str_len(base) - 1));
return el_str_concat(el_str_concat(EL_STR("["), inner), EL_STR(",{\"type\":\"web_search_20250305\",\"name\":\"web_search\",\"max_uses\":5}]"));
return 0;
}
el_val_t str_begins(el_val_t s, el_val_t pre) {
el_val_t n = str_len(pre);
if (str_len(s) < n) {
return 0;
}
return str_eq(str_slice(s, 0, n), pre);
return 0;
}
el_val_t connector_tools_json(void) {
el_val_t raw = exec_capture(EL_STR("curl -s --max-time 2 http://127.0.0.1:7771/mcp/tools"));
if (str_eq(raw, EL_STR(""))) {
return EL_STR("[]");
}
el_val_t arr = json_get_raw(raw, EL_STR("tools"));
if (str_eq(arr, EL_STR(""))) {
return EL_STR("[]");
}
return arr;
return 0;
}
el_val_t agentic_tools_all(void) {
el_val_t base = agentic_tools_with_web();
el_val_t conn = connector_tools_json();
el_val_t conn_inner = str_slice(conn, 1, (str_len(conn) - 1));
if (str_eq(conn_inner, EL_STR(""))) {
return base;
}
el_val_t base_open = str_slice(base, 0, (str_len(base) - 1));
return el_str_concat(el_str_concat(el_str_concat(base_open, EL_STR(",")), conn_inner), EL_STR("]"));
return 0;
}
el_val_t call_mcp_bridge(el_val_t tool_name, el_val_t tool_input) {
el_val_t eff_input = ({ el_val_t _if_result_20 = 0; if (str_eq(tool_input, EL_STR(""))) { _if_result_20 = (EL_STR("{}")); } else { _if_result_20 = (tool_input); } _if_result_20; });
el_val_t body = el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"name\":\""), tool_name), EL_STR("\",\"input\":")), eff_input), EL_STR("}"));
el_val_t tmp = EL_STR("/tmp/neuron-mcp-call.json");
fs_write(tmp, body);
return exec_capture(el_str_concat(EL_STR("curl -s --max-time 30 -X POST http://127.0.0.1:7771/mcp/call -H 'Content-Type: application/json' -d @"), tmp));
return 0;
}
el_val_t tool_auto_approved(el_val_t tool_name) {
if (!str_begins(tool_name, EL_STR("mcp__"))) {
return 0;
}
el_val_t raw = exec_capture(EL_STR("curl -s --max-time 2 http://127.0.0.1:7771/mcp/auto-approved"));
if (str_eq(raw, EL_STR(""))) {
return 0;
}
el_val_t list = json_get_raw(raw, EL_STR("tools"));
if (str_eq(list, EL_STR(""))) {
return 0;
}
return str_contains(list, el_str_concat(el_str_concat(EL_STR("\""), tool_name), EL_STR("\"")));
return 0;
}
el_val_t dispatch_tool(el_val_t tool_name, el_val_t tool_input) {
if (str_eq(tool_name, EL_STR("read_file"))) {
el_val_t path = json_get(tool_input, EL_STR("path"));
@@ -248,6 +325,12 @@ el_val_t dispatch_tool(el_val_t tool_name, el_val_t tool_input) {
el_val_t result = http_get(url);
return json_safe(result);
}
if (str_eq(tool_name, EL_STR("web_search"))) {
el_val_t query = json_get(tool_input, EL_STR("query"));
el_val_t encoded = str_replace(str_replace(str_replace(str_replace(query, EL_STR(" "), EL_STR("+")), EL_STR("\""), EL_STR("")), EL_STR("'"), EL_STR("")), EL_STR("&"), EL_STR("and"));
el_val_t rss = http_get(el_str_concat(el_str_concat(EL_STR("https://news.google.com/rss/search?q="), encoded), EL_STR("&hl=en-US&gl=US&ceid=US:en")));
return json_safe(rss);
}
if (str_eq(tool_name, EL_STR("search_memory"))) {
el_val_t query = json_get(tool_input, EL_STR("query"));
el_val_t result = engram_search_json(query, 10);
@@ -258,80 +341,299 @@ el_val_t dispatch_tool(el_val_t tool_name, el_val_t tool_input) {
el_val_t result = exec_capture(cmd);
return json_safe(result);
}
if (str_begins(tool_name, EL_STR("mcp__"))) {
el_val_t out = call_mcp_bridge(tool_name, tool_input);
if (str_eq(out, EL_STR(""))) {
return json_safe(EL_STR("MCP bridge unreachable (neuron-connectd on :7771)"));
}
el_val_t content = json_get(out, EL_STR("content"));
if (str_eq(content, EL_STR(""))) {
el_val_t err = json_get(out, EL_STR("error"));
el_val_t msg = ({ el_val_t _if_result_21 = 0; if (str_eq(err, EL_STR(""))) { _if_result_21 = (EL_STR("MCP call failed")); } else { _if_result_21 = (el_str_concat(EL_STR("MCP error: "), err)); } _if_result_21; });
return json_safe(msg);
}
return json_safe(content);
}
return el_str_concat(EL_STR("unknown tool: "), tool_name);
return 0;
}
el_val_t json_array_append(el_val_t arr, el_val_t item) {
el_val_t eff = ({ el_val_t _if_result_22 = 0; if (str_eq(arr, EL_STR(""))) { _if_result_22 = (EL_STR("[]")); } else { _if_result_22 = (arr); } _if_result_22; });
el_val_t inner = str_slice(eff, 1, (str_len(eff) - 1));
if (str_eq(inner, EL_STR(""))) {
return el_str_concat(el_str_concat(EL_STR("["), item), EL_STR("]"));
}
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("["), inner), EL_STR(",")), item), EL_STR("]"));
return 0;
}
el_val_t append_tool_log(el_val_t log, el_val_t name) {
el_val_t quoted = el_str_concat(el_str_concat(EL_STR("\""), name), EL_STR("\""));
if (str_eq(log, EL_STR(""))) {
return quoted;
}
return el_str_concat(el_str_concat(log, EL_STR(",")), quoted);
return 0;
}
el_val_t exec_tool_block(el_val_t block) {
el_val_t t_id = json_get(block, EL_STR("id"));
el_val_t t_name = json_get(block, EL_STR("name"));
el_val_t t_input = json_get_raw(block, EL_STR("input"));
el_val_t raw = dispatch_tool(t_name, t_input);
el_val_t trunc = ({ el_val_t _if_result_23 = 0; if ((str_len(raw) > 6000)) { _if_result_23 = (el_str_concat(str_slice(raw, 0, 6000), EL_STR("...[truncated]"))); } else { _if_result_23 = (raw); } _if_result_23; });
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"type\":\"tool_result\",\"tool_use_id\":\""), t_id), EL_STR("\",\"content\":\"")), trunc), EL_STR("\"}"));
return 0;
}
el_val_t agentic_blob(el_val_t model, el_val_t system, el_val_t tools_json, el_val_t messages, el_val_t origin, el_val_t approval, el_val_t iteration, el_val_t tools_log, el_val_t content, el_val_t queue, el_val_t results, el_val_t next) {
el_val_t appr = ({ el_val_t _if_result_24 = 0; if (approval) { _if_result_24 = (EL_STR("true")); } else { _if_result_24 = (EL_STR("false")); } _if_result_24; });
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_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"model\":\""), model), EL_STR("\"")), EL_STR(",\"system\":\"")), json_safe(system)), EL_STR("\"")), EL_STR(",\"origin\":\"")), json_safe(origin)), EL_STR("\"")), EL_STR(",\"approval\":")), appr), EL_STR(",\"iteration\":")), int_to_str(iteration)), EL_STR(",\"next\":")), int_to_str(next)), EL_STR(",\"tools_log\":\"")), json_safe(tools_log)), EL_STR("\"")), EL_STR(",\"tools\":")), tools_json), EL_STR(",\"messages\":")), messages), EL_STR(",\"content\":")), content), EL_STR(",\"queue\":")), queue), EL_STR(",\"results\":")), results), EL_STR("}"));
return 0;
}
el_val_t extract_all_text(el_val_t s) {
el_val_t key = EL_STR("\"text\":\"");
el_val_t klen = str_len(key);
el_val_t n = str_len(s);
el_val_t out = EL_STR("");
el_val_t i = 0;
el_val_t inval = 0;
el_val_t esc = 0;
while (i < n) {
el_val_t at_key = ((!inval && ((i + klen) <= n)) && str_eq(str_slice(s, i, (i + klen)), key));
el_val_t ch = str_slice(s, i, (i + 1));
el_val_t was_esc = esc;
inval = ({ el_val_t _if_result_25 = 0; if (at_key) { _if_result_25 = (1); } else { _if_result_25 = (inval); } _if_result_25; });
el_val_t proc = (inval && !at_key);
esc = ({ el_val_t _if_result_26 = 0; if (((proc && !was_esc) && str_eq(ch, EL_STR("\\")))) { _if_result_26 = (1); } else { _if_result_26 = (0); } _if_result_26; });
el_val_t decoded = ({ el_val_t _if_result_27 = 0; if ((proc && was_esc)) { _if_result_27 = (({ el_val_t _if_result_28 = 0; if (str_eq(ch, EL_STR("n"))) { _if_result_28 = (EL_STR("\n")); } else { _if_result_28 = (({ el_val_t _if_result_29 = 0; if (str_eq(ch, EL_STR("t"))) { _if_result_29 = (EL_STR("\t")); } else { _if_result_29 = (({ el_val_t _if_result_30 = 0; if (str_eq(ch, EL_STR("r"))) { _if_result_30 = (EL_STR("")); } else { _if_result_30 = (({ el_val_t _if_result_31 = 0; if (str_eq(ch, EL_STR("\""))) { _if_result_31 = (EL_STR("\"")); } else { _if_result_31 = (({ el_val_t _if_result_32 = 0; if (str_eq(ch, EL_STR("\\"))) { _if_result_32 = (EL_STR("\\")); } else { _if_result_32 = (({ el_val_t _if_result_33 = 0; if (str_eq(ch, EL_STR("/"))) { _if_result_33 = (EL_STR("/")); } else { _if_result_33 = (ch); } _if_result_33; })); } _if_result_32; })); } _if_result_31; })); } _if_result_30; })); } _if_result_29; })); } _if_result_28; })); } else { _if_result_27 = (ch); } _if_result_27; });
el_val_t end_val = ((proc && !was_esc) && str_eq(ch, EL_STR("\"")));
el_val_t do_app = ((proc && !end_val) && !esc);
out = ({ el_val_t _if_result_34 = 0; if (do_app) { _if_result_34 = (el_str_concat(out, decoded)); } else { _if_result_34 = (out); } _if_result_34; });
inval = ({ el_val_t _if_result_35 = 0; if (end_val) { _if_result_35 = (0); } else { _if_result_35 = (inval); } _if_result_35; });
i = ({ el_val_t _if_result_36 = 0; if (at_key) { _if_result_36 = ((i + klen)); } else { _if_result_36 = ((i + 1)); } _if_result_36; });
}
return out;
return 0;
}
el_val_t strip_citations(el_val_t s) {
el_val_t marker = EL_STR(",\"citations\":[");
el_val_t mlen = str_len(marker);
el_val_t n = str_len(s);
el_val_t out = EL_STR("");
el_val_t i = 0;
el_val_t skip = 0;
while (i < n) {
el_val_t ch = str_slice(s, i, (i + 1));
el_val_t at_marker = (((skip == 0) && ((i + mlen) <= n)) && str_eq(str_slice(s, i, (i + mlen)), marker));
el_val_t was_skip = (skip > 0);
skip = ({ el_val_t _if_result_37 = 0; if (at_marker) { _if_result_37 = (1); } else { _if_result_37 = (({ el_val_t _if_result_38 = 0; if (was_skip) { _if_result_38 = (({ el_val_t _if_result_39 = 0; if (str_eq(ch, EL_STR("["))) { _if_result_39 = ((skip + 1)); } else { _if_result_39 = (({ el_val_t _if_result_40 = 0; if (str_eq(ch, EL_STR("]"))) { _if_result_40 = ((skip - 1)); } else { _if_result_40 = (skip); } _if_result_40; })); } _if_result_39; })); } else { _if_result_38 = (skip); } _if_result_38; })); } _if_result_37; });
out = ({ el_val_t _if_result_41 = 0; if (at_marker) { _if_result_41 = (out); } else { _if_result_41 = (({ el_val_t _if_result_42 = 0; if (was_skip) { _if_result_42 = (out); } else { _if_result_42 = (el_str_concat(out, ch)); } _if_result_42; })); } _if_result_41; });
i = ({ el_val_t _if_result_43 = 0; if (at_marker) { _if_result_43 = ((i + mlen)); } else { _if_result_43 = ((i + 1)); } _if_result_43; });
}
return out;
return 0;
}
el_val_t agentic_api_turn(el_val_t model, el_val_t safe_sys, el_val_t tools_json, el_val_t messages) {
el_val_t api_key = agentic_api_key();
el_val_t api_url = EL_STR("https://api.anthropic.com/v1/messages");
el_val_t h = el_map_new(0);
map_set(h, EL_STR("x-api-key"), api_key);
map_set(h, EL_STR("anthropic-version"), EL_STR("2023-06-01"));
map_set(h, EL_STR("content-type"), EL_STR("application/json"));
el_val_t req_body = 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("{\"model\":\""), model), EL_STR("\"")), EL_STR(",\"max_tokens\":4096")), EL_STR(",\"system\":\"")), safe_sys), EL_STR("\"")), EL_STR(",\"tools\":")), tools_json), EL_STR(",\"messages\":")), messages), EL_STR("}"));
el_val_t raw_resp = http_post_with_headers(api_url, req_body, h);
el_val_t is_error = ((str_starts_with(raw_resp, EL_STR("{\"error\"")) || str_starts_with(raw_resp, EL_STR("{\"type\":\"error\""))) || str_contains(raw_resp, EL_STR("authentication_error")));
if (is_error) {
el_val_t detail_raw = ({ el_val_t _if_result_44 = 0; if ((str_len(raw_resp) > 300)) { _if_result_44 = (str_slice(raw_resp, 0, 300)); } else { _if_result_44 = (raw_resp); } _if_result_44; });
el_val_t detail = json_safe(detail_raw);
return el_str_concat(el_str_concat(EL_STR("{\"kind\":\"error\",\"payload\":{\"error\":\"llm unavailable\",\"reply\":\"\",\"detail\":\""), detail), EL_STR("\"}}"));
}
el_val_t stop_reason = json_get(raw_resp, EL_STR("stop_reason"));
if (str_eq(stop_reason, EL_STR("refusal"))) {
return EL_STR("{\"kind\":\"refusal\"}");
}
el_val_t content_arr = json_get_raw(raw_resp, EL_STR("content"));
el_val_t eff_content = ({ el_val_t _if_result_45 = 0; if (str_eq(content_arr, EL_STR(""))) { _if_result_45 = (EL_STR("[]")); } else { _if_result_45 = (content_arr); } _if_result_45; });
el_val_t walk_content = strip_citations(eff_content);
el_val_t text_out = extract_all_text(walk_content);
el_val_t queue = EL_STR("[]");
el_val_t ci = 0;
el_val_t c_total = json_array_len(eff_content);
while (ci < c_total) {
el_val_t block = json_array_get(eff_content, ci);
el_val_t btype = json_get(block, EL_STR("type"));
queue = ({ el_val_t _if_result_46 = 0; if (str_eq(btype, EL_STR("tool_use"))) { _if_result_46 = (json_array_append(queue, block)); } else { _if_result_46 = (queue); } _if_result_46; });
ci = (ci + 1);
}
el_val_t q_len = json_array_len(queue);
el_val_t is_tool_turn = (str_eq(stop_reason, EL_STR("tool_use")) && (q_len > 0));
if (is_tool_turn) {
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"kind\":\"tools\",\"content\":"), eff_content), EL_STR(",\"queue\":")), queue), EL_STR("}"));
}
if (str_eq(stop_reason, EL_STR("pause_turn"))) {
return el_str_concat(el_str_concat(EL_STR("{\"kind\":\"pause\",\"content\":"), eff_content), EL_STR("}"));
}
return el_str_concat(el_str_concat(EL_STR("{\"kind\":\"final\",\"text\":\""), json_safe(text_out)), EL_STR("\"}"));
return 0;
}
el_val_t agentic_engine(el_val_t session_id, el_val_t blob) {
el_val_t model = json_get(blob, EL_STR("model"));
el_val_t system = json_get(blob, EL_STR("system"));
el_val_t safe_sys = json_safe(system);
el_val_t origin = json_get(blob, EL_STR("origin"));
el_val_t approval = json_get_bool(blob, EL_STR("approval"));
el_val_t tools_json = json_get_raw(blob, EL_STR("tools"));
el_val_t pend_key = el_str_concat(EL_STR("agentic_pending_"), session_id);
el_val_t messages = json_get_raw(blob, EL_STR("messages"));
el_val_t content_in = json_get_raw(blob, EL_STR("content"));
el_val_t queue_in = json_get_raw(blob, EL_STR("queue"));
el_val_t results_in = json_get_raw(blob, EL_STR("results"));
el_val_t content = ({ el_val_t _if_result_47 = 0; if (str_eq(content_in, EL_STR(""))) { _if_result_47 = (EL_STR("[]")); } else { _if_result_47 = (content_in); } _if_result_47; });
el_val_t queue = ({ el_val_t _if_result_48 = 0; if (str_eq(queue_in, EL_STR(""))) { _if_result_48 = (EL_STR("[]")); } else { _if_result_48 = (queue_in); } _if_result_48; });
el_val_t results = ({ el_val_t _if_result_49 = 0; if (str_eq(results_in, EL_STR(""))) { _if_result_49 = (EL_STR("[]")); } else { _if_result_49 = (results_in); } _if_result_49; });
el_val_t next = json_get_int(blob, EL_STR("next"));
el_val_t iteration = json_get_int(blob, EL_STR("iteration"));
el_val_t tools_log = json_get(blob, EL_STR("tools_log"));
el_val_t steps = 0;
while (steps < 100) {
el_val_t q_len = json_array_len(queue);
el_val_t has_pending = (next < q_len);
if (has_pending && approval) {
el_val_t blk_a = json_array_get(queue, next);
el_val_t pend_name = json_get(blk_a, EL_STR("name"));
if (!tool_auto_approved(pend_name)) {
el_val_t park = agentic_blob(model, system, tools_json, messages, origin, approval, iteration, tools_log, content, queue, results, next);
state_set(pend_key, park);
el_val_t t_input = json_get_raw(blk_a, EL_STR("input"));
el_val_t eff_input = ({ el_val_t _if_result_50 = 0; if (str_eq(t_input, EL_STR(""))) { _if_result_50 = (EL_STR("{}")); } else { _if_result_50 = (t_input); } _if_result_50; });
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("{\"status\":\"tool_pending\",\"call_id\":\""), json_get(blk_a, EL_STR("id"))), EL_STR("\",\"tool_name\":\"")), json_get(blk_a, EL_STR("name"))), EL_STR("\",\"tool_input\":")), eff_input), EL_STR(",\"model\":\"")), model), EL_STR("\",\"reply\":\"\"}"));
}
}
el_val_t do_exec = has_pending;
el_val_t do_fold = (!has_pending && (q_len > 0));
el_val_t do_api = (!has_pending && (q_len < 1));
el_val_t blk = ({ el_val_t _if_result_51 = 0; if (do_exec) { _if_result_51 = (json_array_get(queue, next)); } else { _if_result_51 = (EL_STR("")); } _if_result_51; });
el_val_t t_msg = ({ el_val_t _if_result_52 = 0; if (do_exec) { _if_result_52 = (exec_tool_block(blk)); } else { _if_result_52 = (EL_STR("")); } _if_result_52; });
tools_log = ({ el_val_t _if_result_53 = 0; if (do_exec) { _if_result_53 = (append_tool_log(tools_log, json_get(blk, EL_STR("name")))); } else { _if_result_53 = (tools_log); } _if_result_53; });
results = ({ el_val_t _if_result_54 = 0; if (do_exec) { _if_result_54 = (json_array_append(results, t_msg)); } else { _if_result_54 = (results); } _if_result_54; });
next = ({ el_val_t _if_result_55 = 0; if (do_exec) { _if_result_55 = ((next + 1)); } else { _if_result_55 = (next); } _if_result_55; });
messages = ({ el_val_t _if_result_56 = 0; if (do_fold) { _if_result_56 = (json_array_append(json_array_append(messages, el_str_concat(el_str_concat(EL_STR("{\"role\":\"assistant\",\"content\":"), content), EL_STR("}"))), el_str_concat(el_str_concat(EL_STR("{\"role\":\"user\",\"content\":"), results), EL_STR("}")))); } else { _if_result_56 = (messages); } _if_result_56; });
content = ({ el_val_t _if_result_57 = 0; if (do_fold) { _if_result_57 = (EL_STR("[]")); } else { _if_result_57 = (content); } _if_result_57; });
queue = ({ el_val_t _if_result_58 = 0; if (do_fold) { _if_result_58 = (EL_STR("[]")); } else { _if_result_58 = (queue); } _if_result_58; });
results = ({ el_val_t _if_result_59 = 0; if (do_fold) { _if_result_59 = (EL_STR("[]")); } else { _if_result_59 = (results); } _if_result_59; });
next = ({ el_val_t _if_result_60 = 0; if (do_fold) { _if_result_60 = (0); } else { _if_result_60 = (next); } _if_result_60; });
if (do_api && (iteration >= 8)) {
state_set(pend_key, EL_STR(""));
return EL_STR("{\"error\":\"no response\",\"reply\":\"\"}");
}
el_val_t verdict = ({ el_val_t _if_result_61 = 0; if (do_api) { _if_result_61 = (agentic_api_turn(model, safe_sys, tools_json, messages)); } else { _if_result_61 = (EL_STR("")); } _if_result_61; });
el_val_t kind = ({ el_val_t _if_result_62 = 0; if (do_api) { _if_result_62 = (json_get(verdict, EL_STR("kind"))); } else { _if_result_62 = (EL_STR("")); } _if_result_62; });
if (str_eq(kind, EL_STR("error"))) {
state_set(pend_key, EL_STR(""));
return json_get_raw(verdict, EL_STR("payload"));
}
if (str_eq(kind, EL_STR("refusal"))) {
state_set(pend_key, EL_STR(""));
return el_str_concat(el_str_concat(EL_STR("{\"status\":\"ok\",\"reply\":\"I'm not able to help with that request.\",\"model\":\""), model), EL_STR("\",\"agentic\":true,\"tools_used\":[]}"));
}
if (str_eq(kind, EL_STR("final"))) {
state_set(pend_key, EL_STR(""));
el_val_t safe_text = json_safe(json_get(verdict, EL_STR("text")));
el_val_t tools_arr = ({ el_val_t _if_result_63 = 0; if (str_eq(tools_log, EL_STR(""))) { _if_result_63 = (EL_STR("[]")); } else { _if_result_63 = (el_str_concat(el_str_concat(EL_STR("["), tools_log), EL_STR("]"))); } _if_result_63; });
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"status\":\"ok\",\"reply\":\""), safe_text), EL_STR("\",\"model\":\"")), model), EL_STR("\",\"agentic\":true,\"tools_used\":")), tools_arr), EL_STR("}"));
}
el_val_t is_pause = str_eq(kind, EL_STR("pause"));
messages = ({ el_val_t _if_result_64 = 0; if (is_pause) { _if_result_64 = (json_array_append(messages, el_str_concat(el_str_concat(EL_STR("{\"role\":\"assistant\",\"content\":"), json_get_raw(verdict, EL_STR("content"))), EL_STR("}")))); } else { _if_result_64 = (messages); } _if_result_64; });
el_val_t is_tools = str_eq(kind, EL_STR("tools"));
content = ({ el_val_t _if_result_65 = 0; if (is_tools) { _if_result_65 = (json_get_raw(verdict, EL_STR("content"))); } else { _if_result_65 = (content); } _if_result_65; });
queue = ({ el_val_t _if_result_66 = 0; if (is_tools) { _if_result_66 = (json_get_raw(verdict, EL_STR("queue"))); } else { _if_result_66 = (queue); } _if_result_66; });
results = ({ el_val_t _if_result_67 = 0; if (is_tools) { _if_result_67 = (EL_STR("[]")); } else { _if_result_67 = (results); } _if_result_67; });
next = ({ el_val_t _if_result_68 = 0; if (is_tools) { _if_result_68 = (0); } else { _if_result_68 = (next); } _if_result_68; });
iteration = ({ el_val_t _if_result_69 = 0; if (do_api) { _if_result_69 = ((iteration + 1)); } else { _if_result_69 = (iteration); } _if_result_69; });
steps = (steps + 1);
}
state_set(pend_key, EL_STR(""));
return EL_STR("{\"error\":\"agentic engine step limit exceeded\",\"reply\":\"\"}");
return 0;
}
el_val_t handle_chat_agentic(el_val_t body) {
el_val_t message = json_get(body, EL_STR("message"));
if (str_eq(message, EL_STR(""))) {
return EL_STR("{\"error\":\"message required\",\"reply\":\"\"}");
}
el_val_t req_model = json_get(body, EL_STR("model"));
el_val_t model = ({ el_val_t _if_result_20 = 0; if (str_eq(req_model, EL_STR(""))) { _if_result_20 = (chat_default_model()); } else { _if_result_20 = (req_model); } _if_result_20; });
el_val_t model = ({ el_val_t _if_result_70 = 0; if (str_eq(req_model, EL_STR(""))) { _if_result_70 = (chat_default_model()); } else { _if_result_70 = (req_model); } _if_result_70; });
el_val_t session_id = json_get(body, EL_STR("session_id"));
el_val_t ra_bool = json_get_bool(body, EL_STR("require_approval"));
el_val_t ra_raw = json_get_raw(body, EL_STR("require_approval"));
el_val_t want_approval = ((ra_bool || str_eq(ra_raw, EL_STR("1"))) || str_eq(ra_raw, EL_STR("true")));
el_val_t approval = (want_approval && !str_eq(session_id, EL_STR("")));
el_val_t ctx = engram_compile(message);
el_val_t identity = state_get(EL_STR("soul_identity"));
el_val_t system = el_str_concat(el_str_concat(identity, EL_STR(" You have access to tools: read files, write files, browse the web, search your memory, run commands. Use them when they add genuine value. Be direct.\n\n")), ctx);
el_val_t api_key = agentic_api_key();
el_val_t tools_json = agentic_tools_literal();
el_val_t current_date = time_format(time_now(), EL_STR("%A, %B %d, %Y"));
el_val_t web_directive = el_str_concat(el_str_concat(EL_STR(" Today's date is "), current_date), EL_STR(". You have a web_search tool that returns live results from the internet. For ANY question about current events, live scores, standings, schedules, recent news, people, prices, or anything that may have changed since your training, you MUST call web_search immediately and answer from the results. Do NOT ask the user to clarify first, do NOT say you lack live access, and do NOT answer time-sensitive questions from memory alone \xe2\x80\x94 search, then answer. When a question is ambiguous about timeframe (e.g. 'the tournament', 'the game', 'the playoffs'), assume the user means whatever is happening or most recent RIGHT NOW as of today's date, search for that, and lead with it."));
el_val_t system = el_str_concat(el_str_concat(el_str_concat(el_str_concat(identity, EL_STR(" You have access to tools: read files, write files, browse the web, search your memory, run commands, plus any connected MCP tools (named mcp__<server>__<tool>). Use them when they add genuine value. Be direct.")), web_directive), EL_STR("\n\n")), ctx);
el_val_t tools_json = agentic_tools_all();
el_val_t safe_msg = json_safe(message);
el_val_t safe_sys = json_safe(system);
el_val_t messages = el_str_concat(el_str_concat(EL_STR("[{\"role\":\"user\",\"content\":\""), safe_msg), EL_STR("\"}]"));
el_val_t api_url = EL_STR("https://api.anthropic.com/v1/messages");
el_val_t h = el_map_new(0);
map_set(h, EL_STR("x-api-key"), api_key);
map_set(h, EL_STR("anthropic-version"), EL_STR("2023-06-01"));
map_set(h, EL_STR("content-type"), EL_STR("application/json"));
el_val_t final_text = EL_STR("");
el_val_t tools_log = EL_STR("");
el_val_t iteration = 0;
el_val_t keep_going = 1;
while (keep_going && (iteration < 8)) {
el_val_t req_body = 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("{\"model\":\""), model), EL_STR("\"")), EL_STR(",\"max_tokens\":4096")), EL_STR(",\"system\":\"")), safe_sys), EL_STR("\"")), EL_STR(",\"tools\":")), tools_json), EL_STR(",\"messages\":")), messages), EL_STR("}"));
el_val_t raw_resp = http_post_with_headers(api_url, req_body, h);
el_val_t is_error = ((str_starts_with(raw_resp, EL_STR("{\"error\"")) || str_starts_with(raw_resp, EL_STR("{\"type\":\"error\""))) || str_contains(raw_resp, EL_STR("authentication_error")));
if (is_error) {
return EL_STR("{\"error\":\"llm unavailable\",\"reply\":\"\"}");
}
el_val_t stop_reason = json_get(raw_resp, EL_STR("stop_reason"));
el_val_t content_arr = json_get_raw(raw_resp, EL_STR("content"));
el_val_t eff_content = ({ el_val_t _if_result_21 = 0; if (str_eq(content_arr, EL_STR(""))) { _if_result_21 = (EL_STR("[]")); } else { _if_result_21 = (content_arr); } _if_result_21; });
el_val_t text_out = EL_STR("");
el_val_t has_tool = 0;
el_val_t tool_id = EL_STR("");
el_val_t tool_name = EL_STR("");
el_val_t tool_input = EL_STR("");
el_val_t ci = 0;
el_val_t c_total = json_array_len(eff_content);
while (ci < c_total) {
el_val_t block = json_array_get(eff_content, ci);
el_val_t btype = json_get(block, EL_STR("type"));
text_out = ({ el_val_t _if_result_22 = 0; if (str_eq(btype, EL_STR("text"))) { _if_result_22 = (el_str_concat(text_out, json_get(block, EL_STR("text")))); } else { _if_result_22 = (text_out); } _if_result_22; });
el_val_t is_new_tool = (str_eq(btype, EL_STR("tool_use")) && !has_tool);
has_tool = ({ el_val_t _if_result_23 = 0; if (is_new_tool) { _if_result_23 = (1); } else { _if_result_23 = (has_tool); } _if_result_23; });
tool_id = ({ el_val_t _if_result_24 = 0; if (is_new_tool) { _if_result_24 = (json_get(block, EL_STR("id"))); } else { _if_result_24 = (tool_id); } _if_result_24; });
tool_name = ({ el_val_t _if_result_25 = 0; if (is_new_tool) { _if_result_25 = (json_get(block, EL_STR("name"))); } else { _if_result_25 = (tool_name); } _if_result_25; });
tool_input = ({ el_val_t _if_result_26 = 0; if (is_new_tool) { _if_result_26 = (json_get_raw(block, EL_STR("input"))); } else { _if_result_26 = (tool_input); } _if_result_26; });
ci = (ci + 1);
}
el_val_t tool_result_raw = ({ el_val_t _if_result_27 = 0; if (has_tool) { _if_result_27 = (dispatch_tool(tool_name, tool_input)); } else { _if_result_27 = (EL_STR("")); } _if_result_27; });
el_val_t tool_result = ({ el_val_t _if_result_28 = 0; if ((str_len(tool_result_raw) > 6000)) { _if_result_28 = (el_str_concat(str_slice(tool_result_raw, 0, 6000), EL_STR("...[truncated]"))); } else { _if_result_28 = (tool_result_raw); } _if_result_28; });
el_val_t tool_msg = el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"type\":\"tool_result\",\"tool_use_id\":\""), tool_id), EL_STR("\",\"content\":\"")), tool_result), EL_STR("\"}"));
el_val_t tool_quoted = el_str_concat(el_str_concat(EL_STR("\""), tool_name), EL_STR("\""));
tools_log = ({ el_val_t _if_result_29 = 0; if (has_tool) { _if_result_29 = (({ el_val_t _if_result_30 = 0; if (str_eq(tools_log, EL_STR(""))) { _if_result_30 = (tool_quoted); } else { _if_result_30 = (el_str_concat(el_str_concat(tools_log, EL_STR(",")), tool_quoted)); } _if_result_30; })); } else { _if_result_29 = (tools_log); } _if_result_29; });
el_val_t is_tool_turn = (str_eq(stop_reason, EL_STR("tool_use")) && has_tool);
el_val_t inner = str_slice(messages, 1, (str_len(messages) - 1));
messages = ({ el_val_t _if_result_31 = 0; if (is_tool_turn) { _if_result_31 = (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("["), inner), EL_STR(",{\"role\":\"assistant\",\"content\":")), eff_content), EL_STR("}")), EL_STR(",{\"role\":\"user\",\"content\":[")), tool_msg), EL_STR("]}")), EL_STR("]"))); } else { _if_result_31 = (messages); } _if_result_31; });
final_text = ({ el_val_t _if_result_32 = 0; if (!is_tool_turn) { _if_result_32 = (text_out); } else { _if_result_32 = (final_text); } _if_result_32; });
keep_going = ({ el_val_t _if_result_33 = 0; if (!is_tool_turn) { _if_result_33 = (0); } else { _if_result_33 = (keep_going); } _if_result_33; });
iteration = (iteration + 1);
if (!str_eq(session_id, EL_STR(""))) {
state_set(el_str_concat(EL_STR("agentic_pending_"), session_id), EL_STR(""));
}
if (str_eq(final_text, EL_STR(""))) {
return EL_STR("{\"error\":\"no response\",\"reply\":\"\"}");
el_val_t blob = agentic_blob(model, system, tools_json, messages, message, approval, 0, EL_STR(""), EL_STR("[]"), EL_STR("[]"), EL_STR("[]"), 0);
return agentic_engine(session_id, blob);
return 0;
}
el_val_t handle_session_approve(el_val_t session_id, el_val_t body) {
if (str_eq(session_id, EL_STR(""))) {
return EL_STR("{\"error\":\"session_id required\",\"reply\":\"\"}");
}
el_val_t safe_text = json_safe(final_text);
el_val_t tools_arr = ({ el_val_t _if_result_34 = 0; if (str_eq(tools_log, EL_STR(""))) { _if_result_34 = (EL_STR("[]")); } else { _if_result_34 = (el_str_concat(el_str_concat(EL_STR("["), tools_log), EL_STR("]"))); } _if_result_34; });
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"reply\":\""), safe_text), EL_STR("\",\"model\":\"")), model), EL_STR("\",\"agentic\":true,\"tools_used\":")), tools_arr), EL_STR("}"));
el_val_t pend_key = el_str_concat(EL_STR("agentic_pending_"), session_id);
el_val_t blob = state_get(pend_key);
if (str_eq(blob, EL_STR(""))) {
return EL_STR("{\"error\":\"no pending tool call for this session\",\"reply\":\"\"}");
}
el_val_t call_id = json_get(body, EL_STR("call_id"));
el_val_t action = json_get(body, EL_STR("action"));
el_val_t queue = json_get_raw(blob, EL_STR("queue"));
el_val_t next = json_get_int(blob, EL_STR("next"));
el_val_t q_len = json_array_len(queue);
if (next >= q_len) {
state_set(pend_key, EL_STR(""));
return EL_STR("{\"error\":\"pending state corrupt\",\"reply\":\"\"}");
}
el_val_t block = json_array_get(queue, next);
el_val_t block_id = json_get(block, EL_STR("id"));
if (!str_eq(call_id, block_id)) {
return EL_STR("{\"error\":\"stale call_id\",\"reply\":\"\"}");
}
el_val_t deny = str_eq(action, EL_STR("deny"));
el_val_t t_msg = ({ el_val_t _if_result_71 = 0; if (deny) { _if_result_71 = (el_str_concat(el_str_concat(EL_STR("{\"type\":\"tool_result\",\"tool_use_id\":\""), block_id), EL_STR("\",\"content\":\"User denied this tool call.\"}"))); } else { _if_result_71 = (exec_tool_block(block)); } _if_result_71; });
el_val_t tools_log_in = json_get(blob, EL_STR("tools_log"));
el_val_t tools_log = ({ el_val_t _if_result_72 = 0; if (deny) { _if_result_72 = (tools_log_in); } else { _if_result_72 = (append_tool_log(tools_log_in, json_get(block, EL_STR("name")))); } _if_result_72; });
el_val_t results = json_array_append(json_get_raw(blob, EL_STR("results")), t_msg);
el_val_t model = json_get(blob, EL_STR("model"));
el_val_t system = json_get(blob, EL_STR("system"));
el_val_t origin = json_get(blob, EL_STR("origin"));
el_val_t tools_json = json_get_raw(blob, EL_STR("tools"));
el_val_t messages = json_get_raw(blob, EL_STR("messages"));
el_val_t content = json_get_raw(blob, EL_STR("content"));
el_val_t iteration = json_get_int(blob, EL_STR("iteration"));
state_set(pend_key, EL_STR(""));
el_val_t updated = agentic_blob(model, system, tools_json, messages, origin, 1, iteration, tools_log, content, queue, results, (next + 1));
el_val_t reply = agentic_engine(session_id, updated);
el_val_t is_final = str_contains(reply, EL_STR("\"status\":\"ok\""));
if (is_final) {
auto_persist(el_str_concat(el_str_concat(EL_STR("{\"message\":\""), json_safe(origin)), EL_STR("\"}")), reply);
}
return reply;
return 0;
}
@@ -346,12 +648,12 @@ el_val_t handle_chat_as_soul(el_val_t body) {
}
el_val_t message = json_get(body, EL_STR("message"));
el_val_t transcript = json_get(body, EL_STR("transcript"));
el_val_t eff_message = ({ el_val_t _if_result_35 = 0; if (str_eq(message, EL_STR(""))) { _if_result_35 = (transcript); } else { _if_result_35 = (message); } _if_result_35; });
el_val_t eff_message = ({ el_val_t _if_result_73 = 0; if (str_eq(message, EL_STR(""))) { _if_result_73 = (transcript); } else { _if_result_73 = (message); } _if_result_73; });
if (str_eq(eff_message, EL_STR(""))) {
return el_str_concat(el_str_concat(EL_STR("{\"error\":\"message or transcript is required\",\"response\":\"\",\"speaker_slug\":\""), speaker), EL_STR("\"}"));
}
el_val_t req_model = json_get(body, EL_STR("model"));
el_val_t model = ({ el_val_t _if_result_36 = 0; if (str_eq(req_model, EL_STR(""))) { _if_result_36 = (chat_default_model()); } else { _if_result_36 = (req_model); } _if_result_36; });
el_val_t model = ({ el_val_t _if_result_74 = 0; if (str_eq(req_model, EL_STR(""))) { _if_result_74 = (chat_default_model()); } else { _if_result_74 = (req_model); } _if_result_74; });
el_val_t raw_response = llm_call_system(model, system_prompt, eff_message);
el_val_t is_error = ((str_starts_with(raw_response, EL_STR("{\"error\"")) || str_starts_with(raw_response, EL_STR("{\"type\":\"error\""))) || str_contains(raw_response, EL_STR("authentication_error")));
if (is_error) {
@@ -373,7 +675,7 @@ el_val_t handle_dharma_room_turn(el_val_t body) {
return el_str_concat(el_str_concat(EL_STR("{\"error\":\"transcript is required\",\"response\":\"\",\"cgi_id\":\""), cgi_id), EL_STR("\"}"));
}
el_val_t engram_ctx = engram_compile(transcript);
el_val_t system_prompt = ({ el_val_t _if_result_37 = 0; if (str_eq(engram_ctx, EL_STR(""))) { _if_result_37 = (identity); } else { _if_result_37 = (el_str_concat(el_str_concat(identity, EL_STR("\n\n")), engram_ctx)); } _if_result_37; });
el_val_t system_prompt = ({ el_val_t _if_result_75 = 0; if (str_eq(engram_ctx, EL_STR(""))) { _if_result_75 = (identity); } else { _if_result_75 = (el_str_concat(el_str_concat(identity, EL_STR("\n\n")), engram_ctx)); } _if_result_75; });
el_val_t raw_response = llm_call_system(model, system_prompt, transcript);
el_val_t is_error = ((str_starts_with(raw_response, EL_STR("{\"error\"")) || str_starts_with(raw_response, EL_STR("{\"type\":\"error\""))) || str_contains(raw_response, EL_STR("authentication_error")));
if (is_error) {
@@ -400,65 +702,19 @@ el_val_t handle_dharma_room_turn_agentic(el_val_t body) {
}
el_val_t ctx = engram_compile(transcript);
el_val_t system = el_str_concat(el_str_concat(identity, EL_STR(" You have access to tools: read files, write files, browse the web, search your memory, run commands. Use them when they add genuine value. Be direct and stay in character.\n\n")), ctx);
el_val_t api_key = agentic_api_key();
el_val_t tools_json = agentic_tools_literal();
el_val_t safe_transcript = json_safe(transcript);
el_val_t safe_sys = json_safe(system);
el_val_t messages = el_str_concat(el_str_concat(EL_STR("[{\"role\":\"user\",\"content\":\""), safe_transcript), EL_STR("\"}]"));
el_val_t api_url = EL_STR("https://api.anthropic.com/v1/messages");
el_val_t h = el_map_new(0);
map_set(h, EL_STR("x-api-key"), api_key);
map_set(h, EL_STR("anthropic-version"), EL_STR("2023-06-01"));
map_set(h, EL_STR("content-type"), EL_STR("application/json"));
el_val_t final_text = EL_STR("");
el_val_t tools_log = EL_STR("");
el_val_t iteration = 0;
el_val_t keep_going = 1;
while (keep_going && (iteration < 8)) {
el_val_t req_body = 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("{\"model\":\""), model), EL_STR("\"")), EL_STR(",\"max_tokens\":4096")), EL_STR(",\"system\":\"")), safe_sys), EL_STR("\"")), EL_STR(",\"tools\":")), tools_json), EL_STR(",\"messages\":")), messages), EL_STR("}"));
el_val_t raw_resp = http_post_with_headers(api_url, req_body, h);
el_val_t is_error = ((str_starts_with(raw_resp, EL_STR("{\"error\"")) || str_starts_with(raw_resp, EL_STR("{\"type\":\"error\""))) || str_contains(raw_resp, EL_STR("authentication_error")));
if (is_error) {
return el_str_concat(el_str_concat(EL_STR("{\"error\":\"llm unavailable\",\"response\":\"\",\"cgi_id\":\""), cgi_id), EL_STR("\"}"));
}
el_val_t stop_reason = json_get(raw_resp, EL_STR("stop_reason"));
el_val_t content_arr = json_get_raw(raw_resp, EL_STR("content"));
el_val_t eff_content = ({ el_val_t _if_result_38 = 0; if (str_eq(content_arr, EL_STR(""))) { _if_result_38 = (EL_STR("[]")); } else { _if_result_38 = (content_arr); } _if_result_38; });
el_val_t text_out = EL_STR("");
el_val_t has_tool = 0;
el_val_t tool_id = EL_STR("");
el_val_t tool_name = EL_STR("");
el_val_t tool_input = EL_STR("");
el_val_t ci = 0;
el_val_t c_total = json_array_len(eff_content);
while (ci < c_total) {
el_val_t block = json_array_get(eff_content, ci);
el_val_t btype = json_get(block, EL_STR("type"));
text_out = ({ el_val_t _if_result_39 = 0; if (str_eq(btype, EL_STR("text"))) { _if_result_39 = (el_str_concat(text_out, json_get(block, EL_STR("text")))); } else { _if_result_39 = (text_out); } _if_result_39; });
el_val_t is_new_tool = (str_eq(btype, EL_STR("tool_use")) && !has_tool);
has_tool = ({ el_val_t _if_result_40 = 0; if (is_new_tool) { _if_result_40 = (1); } else { _if_result_40 = (has_tool); } _if_result_40; });
tool_id = ({ el_val_t _if_result_41 = 0; if (is_new_tool) { _if_result_41 = (json_get(block, EL_STR("id"))); } else { _if_result_41 = (tool_id); } _if_result_41; });
tool_name = ({ el_val_t _if_result_42 = 0; if (is_new_tool) { _if_result_42 = (json_get(block, EL_STR("name"))); } else { _if_result_42 = (tool_name); } _if_result_42; });
tool_input = ({ el_val_t _if_result_43 = 0; if (is_new_tool) { _if_result_43 = (json_get_raw(block, EL_STR("input"))); } else { _if_result_43 = (tool_input); } _if_result_43; });
ci = (ci + 1);
}
el_val_t tool_result_raw = ({ el_val_t _if_result_44 = 0; if (has_tool) { _if_result_44 = (dispatch_tool(tool_name, tool_input)); } else { _if_result_44 = (EL_STR("")); } _if_result_44; });
el_val_t tool_result = ({ el_val_t _if_result_45 = 0; if ((str_len(tool_result_raw) > 6000)) { _if_result_45 = (el_str_concat(str_slice(tool_result_raw, 0, 6000), EL_STR("...[truncated]"))); } else { _if_result_45 = (tool_result_raw); } _if_result_45; });
el_val_t tool_msg = el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"type\":\"tool_result\",\"tool_use_id\":\""), tool_id), EL_STR("\",\"content\":\"")), tool_result), EL_STR("\"}"));
el_val_t tool_quoted = el_str_concat(el_str_concat(EL_STR("\""), tool_name), EL_STR("\""));
tools_log = ({ el_val_t _if_result_46 = 0; if (has_tool) { _if_result_46 = (({ el_val_t _if_result_47 = 0; if (str_eq(tools_log, EL_STR(""))) { _if_result_47 = (tool_quoted); } else { _if_result_47 = (el_str_concat(el_str_concat(tools_log, EL_STR(",")), tool_quoted)); } _if_result_47; })); } else { _if_result_46 = (tools_log); } _if_result_46; });
el_val_t is_tool_turn = (str_eq(stop_reason, EL_STR("tool_use")) && has_tool);
el_val_t inner = str_slice(messages, 1, (str_len(messages) - 1));
messages = ({ el_val_t _if_result_48 = 0; if (is_tool_turn) { _if_result_48 = (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("["), inner), EL_STR(",{\"role\":\"assistant\",\"content\":")), eff_content), EL_STR("}")), EL_STR(",{\"role\":\"user\",\"content\":[")), tool_msg), EL_STR("]}")), EL_STR("]"))); } else { _if_result_48 = (messages); } _if_result_48; });
final_text = ({ el_val_t _if_result_49 = 0; if (!is_tool_turn) { _if_result_49 = (text_out); } else { _if_result_49 = (final_text); } _if_result_49; });
keep_going = ({ el_val_t _if_result_50 = 0; if (!is_tool_turn) { _if_result_50 = (0); } else { _if_result_50 = (keep_going); } _if_result_50; });
iteration = (iteration + 1);
el_val_t blob = agentic_blob(model, system, tools_json, messages, transcript, 0, 0, EL_STR(""), EL_STR("[]"), EL_STR("[]"), EL_STR("[]"), 0);
el_val_t reply = agentic_engine(EL_STR(""), blob);
el_val_t err = json_get(reply, EL_STR("error"));
if (!str_eq(err, EL_STR(""))) {
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"error\":\""), json_safe(err)), EL_STR("\",\"response\":\"\",\"cgi_id\":\"")), cgi_id), EL_STR("\"}"));
}
if (str_eq(final_text, EL_STR(""))) {
return el_str_concat(el_str_concat(EL_STR("{\"error\":\"no response\",\"response\":\"\",\"cgi_id\":\""), cgi_id), EL_STR("\"}"));
}
el_val_t safe_text = json_safe(final_text);
el_val_t tools_arr = ({ el_val_t _if_result_51 = 0; if (str_eq(tools_log, EL_STR(""))) { _if_result_51 = (EL_STR("[]")); } else { _if_result_51 = (el_str_concat(el_str_concat(EL_STR("["), tools_log), EL_STR("]"))); } _if_result_51; });
el_val_t text = json_get(reply, EL_STR("reply"));
el_val_t safe_text = json_safe(text);
el_val_t tools_used = json_get_raw(reply, EL_STR("tools_used"));
el_val_t tools_arr = ({ el_val_t _if_result_76 = 0; if (str_eq(tools_used, EL_STR(""))) { _if_result_76 = (EL_STR("[]")); } else { _if_result_76 = (tools_used); } _if_result_76; });
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"response\":\""), safe_text), EL_STR("\",\"cgi_id\":\"")), cgi_id), EL_STR("\",\"tools_used\":")), tools_arr), EL_STR("}"));
return 0;
}
@@ -466,7 +722,7 @@ el_val_t handle_dharma_room_turn_agentic(el_val_t body) {
el_val_t auto_persist(el_val_t req, el_val_t resp) {
el_val_t message = json_get(req, EL_STR("message"));
el_val_t reply = json_get(resp, EL_STR("response"));
el_val_t reply2 = ({ el_val_t _if_result_52 = 0; if (str_eq(reply, EL_STR(""))) { _if_result_52 = (json_get(resp, EL_STR("reply"))); } else { _if_result_52 = (reply); } _if_result_52; });
el_val_t reply2 = ({ el_val_t _if_result_77 = 0; if (str_eq(reply, EL_STR(""))) { _if_result_77 = (json_get(resp, EL_STR("reply"))); } else { _if_result_77 = (reply); } _if_result_77; });
if (str_eq(message, EL_STR(""))) {
return EL_STR("");
}