diff --git a/chat.el b/chat.el index 1df794e..edddcee 100644 --- a/chat.el +++ b/chat.el @@ -265,12 +265,9 @@ fn handle_chat_agentic(body: String) -> String { let api_key: String = agentic_api_key() let tools_json: String = agentic_tools_literal() - - // Build initial messages array let safe_msg: String = json_safe(message) let safe_sys: String = json_safe(system) let messages: String = "[{\"role\":\"user\",\"content\":\"" + safe_msg + "\"}]" - let api_url: String = "https://api.anthropic.com/v1/messages" let h: Map = {} map_set(h, "x-api-key", api_key) @@ -299,47 +296,55 @@ fn handle_chat_agentic(body: String) -> String { } let stop_reason: String = json_get(raw_resp, "stop_reason") - let content_arr: String = json_get(raw_resp, "content") + // json_get_raw needed — content is an array, json_get returns "" for non-strings + let content_arr: String = json_get_raw(raw_resp, "content") + let eff_content: String = if str_eq(content_arr, "") { "[]" } else { content_arr } - // Collect text and tool_use blocks from content + // Walk content blocks. El rule: mutations must be at top level of while body + // using if-expressions — mutations inside if *blocks* don't escape scope. let text_out: String = "" - let tool_results: String = "" - let has_tool_use: Bool = false + let has_tool: Bool = false + let tool_id: String = "" + let tool_name: String = "" + let tool_input: String = "" let ci: Int = 0 - let c_total: Int = json_array_len(content_arr) + let c_total: Int = json_array_len(eff_content) while ci < c_total { - let block: String = json_array_get(content_arr, ci) - let block_type: String = json_get(block, "type") - if str_eq(block_type, "text") { - let block_text: String = json_get(block, "text") - let text_out = text_out + block_text - } - if str_eq(block_type, "tool_use") { - let has_tool_use = true - let tool_id: String = json_get(block, "id") - let tool_name: String = json_get(block, "name") - let tool_input: String = json_get(block, "input") - let tool_result: String = dispatch_tool(tool_name, tool_input) - let sep: String = if str_eq(tool_results, "") { "" } else { "," } - let tool_results = tool_results + sep - + "{\"type\":\"tool_result\",\"tool_use_id\":\"" + tool_id + "\",\"content\":\"" + tool_result + "\"}" - } + let block: String = json_array_get(eff_content, ci) + let btype: String = json_get(block, "type") + // Accumulate text at top level using if-expression + let text_out = if str_eq(btype, "text") { text_out + json_get(block, "text") } else { text_out } + // Capture first tool_use block only + let is_new_tool: Bool = str_eq(btype, "tool_use") && !has_tool + let has_tool = if is_new_tool { true } else { has_tool } + let tool_id = if is_new_tool { json_get(block, "id") } else { tool_id } + let tool_name = if is_new_tool { json_get(block, "name") } else { tool_name } + // input is a JSON object — must use json_get_raw, not json_get + let tool_input = if is_new_tool { json_get_raw(block, "input") } else { tool_input } let ci = ci + 1 } - if str_eq(stop_reason, "tool_use") && has_tool_use { - // Append assistant turn with its content blocks, then tool results - let safe_content_arr: String = json_safe(content_arr) - let inner_msgs: String = str_slice(messages, 1, str_len(messages) - 1) - let messages = "[" + inner_msgs - + ",{\"role\":\"assistant\",\"content\":" + content_arr + "}" - + ",{\"role\":\"user\",\"content\":[" + tool_results + "]}" - + "]" - let iteration = iteration + 1 - } else { - let final_text = text_out - let keep_going = false - } + // Dispatch tool and build result message + let tool_result_raw: String = if has_tool { dispatch_tool(tool_name, tool_input) } else { "" } + // Truncate large tool results (web pages etc) to avoid oversized requests + let tool_result: String = if str_len(tool_result_raw) > 6000 { + str_slice(tool_result_raw, 0, 6000) + "...[truncated]" + } else { tool_result_raw } + + let tool_msg: String = "{\"type\":\"tool_result\",\"tool_use_id\":\"" + tool_id + "\",\"content\":\"" + tool_result + "\"}" + + // Update messages and loop state — all at top level using if-expressions + let is_tool_turn: Bool = str_eq(stop_reason, "tool_use") && has_tool + let inner: String = str_slice(messages, 1, str_len(messages) - 1) + let messages = if is_tool_turn { + "[" + inner + + ",{\"role\":\"assistant\",\"content\":" + eff_content + "}" + + ",{\"role\":\"user\",\"content\":[" + tool_msg + "]}" + + "]" + } else { messages } + let final_text = if !is_tool_turn { text_out } else { final_text } + let keep_going = if !is_tool_turn { false } else { keep_going } + let iteration = iteration + 1 } if str_eq(final_text, "") { diff --git a/chat.elh b/chat.elh index cf0dd77..5327ec2 100644 --- a/chat.elh +++ b/chat.elh @@ -9,6 +9,9 @@ extern fn clean_llm_response(s: String) -> String extern fn handle_chat(body: String) -> String extern fn handle_see(body: String) -> String extern fn studio_tools_json() -> String +extern fn agentic_api_key() -> String +extern fn agentic_tools_literal() -> String +extern fn dispatch_tool(tool_name: String, tool_input: String) -> String extern fn handle_chat_agentic(body: String) -> String extern fn handle_chat_as_soul(body: String) -> String extern fn auto_persist(req: String, resp: String) -> Void diff --git a/dist/chat.c b/dist/chat.c index 249774e..27352c2 100644 --- a/dist/chat.c +++ b/dist/chat.c @@ -24,6 +24,9 @@ el_val_t clean_llm_response(el_val_t s); el_val_t handle_chat(el_val_t body); 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 dispatch_tool(el_val_t tool_name, el_val_t tool_input); el_val_t handle_chat_agentic(el_val_t body); el_val_t handle_chat_as_soul(el_val_t body); el_val_t auto_persist(el_val_t req, el_val_t resp); @@ -171,6 +174,51 @@ el_val_t studio_tools_json(void) { return 0; } +el_val_t agentic_api_key(void) { + el_val_t k1 = env(EL_STR("ANTHROPIC_API_KEY")); + if (!str_eq(k1, EL_STR(""))) { + return k1; + } + return env(EL_STR("NEURON_LLM_0_KEY")); + return 0; +} + +el_val_t agentic_tools_literal(void) { + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("["), EL_STR("{\"name\":\"read_file\",\"description\":\"Read contents of a file from disk.\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"path\":{\"type\":\"string\",\"description\":\"Absolute file path\"}},\"required\":[\"path\"]}},")), EL_STR("{\"name\":\"write_file\",\"description\":\"Write content to a file on disk.\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"path\":{\"type\":\"string\"},\"content\":{\"type\":\"string\"}},\"required\":[\"path\",\"content\"]}},")), EL_STR("{\"name\":\"web_get\",\"description\":\"Fetch content from a URL.\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"url\":{\"type\":\"string\"}},\"required\":[\"url\"]}},")), EL_STR("{\"name\":\"search_memory\",\"description\":\"Search engram memory for relevant nodes.\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\"}},\"required\":[\"query\"]}},")), EL_STR("{\"name\":\"run_command\",\"description\":\"Run a shell command and capture output.\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"command\":{\"type\":\"string\"}},\"required\":[\"command\"]}}")), 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")); + el_val_t content = fs_read(path); + return json_safe(content); + } + if (str_eq(tool_name, EL_STR("write_file"))) { + el_val_t path = json_get(tool_input, EL_STR("path")); + el_val_t content = json_get(tool_input, EL_STR("content")); + fs_write(path, content); + return EL_STR("{\\\"ok\\\":true}"); + } + if (str_eq(tool_name, EL_STR("web_get"))) { + el_val_t url = json_get(tool_input, EL_STR("url")); + el_val_t result = http_get(url); + return json_safe(result); + } + 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); + return json_safe(result); + } + if (str_eq(tool_name, EL_STR("run_command"))) { + el_val_t cmd = json_get(tool_input, EL_STR("command")); + el_val_t result = exec_capture(cmd); + return json_safe(result); + } + return el_str_concat(EL_STR("unknown tool: "), tool_name); + 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(""))) { @@ -181,12 +229,61 @@ el_val_t handle_chat_agentic(el_val_t body) { 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 tools = studio_tools_json(); - el_val_t text = llm_call_agentic(model, system, message, tools); - if (str_eq(text, EL_STR(""))) { + el_val_t api_key = agentic_api_key(); + el_val_t tools_json = agentic_tools_literal(); + 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 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_19 = 0; if (str_eq(content_arr, EL_STR(""))) { _if_result_19 = (EL_STR("[]")); } else { _if_result_19 = (content_arr); } _if_result_19; }); + 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_20 = 0; if (str_eq(btype, EL_STR("text"))) { _if_result_20 = (el_str_concat(text_out, json_get(block, EL_STR("text")))); } else { _if_result_20 = (text_out); } _if_result_20; }); + el_val_t is_new_tool = (str_eq(btype, EL_STR("tool_use")) && !has_tool); + has_tool = ({ el_val_t _if_result_21 = 0; if (is_new_tool) { _if_result_21 = (1); } else { _if_result_21 = (has_tool); } _if_result_21; }); + tool_id = ({ el_val_t _if_result_22 = 0; if (is_new_tool) { _if_result_22 = (json_get(block, EL_STR("id"))); } else { _if_result_22 = (tool_id); } _if_result_22; }); + tool_name = ({ el_val_t _if_result_23 = 0; if (is_new_tool) { _if_result_23 = (json_get(block, EL_STR("name"))); } else { _if_result_23 = (tool_name); } _if_result_23; }); + tool_input = ({ el_val_t _if_result_24 = 0; if (is_new_tool) { _if_result_24 = (json_get_raw(block, EL_STR("input"))); } else { _if_result_24 = (tool_input); } _if_result_24; }); + ci = (ci + 1); + } + el_val_t tool_result_raw = ({ el_val_t _if_result_25 = 0; if (has_tool) { _if_result_25 = (dispatch_tool(tool_name, tool_input)); } else { _if_result_25 = (EL_STR("")); } _if_result_25; }); + el_val_t tool_result = ({ el_val_t _if_result_26 = 0; if ((str_len(tool_result_raw) > 6000)) { _if_result_26 = (el_str_concat(str_slice(tool_result_raw, 0, 6000), EL_STR("...[truncated]"))); } else { _if_result_26 = (tool_result_raw); } _if_result_26; }); + 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 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_27 = 0; if (is_tool_turn) { _if_result_27 = (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_27 = (messages); } _if_result_27; }); + final_text = ({ el_val_t _if_result_28 = 0; if (!is_tool_turn) { _if_result_28 = (text_out); } else { _if_result_28 = (final_text); } _if_result_28; }); + keep_going = ({ el_val_t _if_result_29 = 0; if (!is_tool_turn) { _if_result_29 = (0); } else { _if_result_29 = (keep_going); } _if_result_29; }); + iteration = (iteration + 1); + } + if (str_eq(final_text, EL_STR(""))) { return EL_STR("{\"error\":\"no response\",\"reply\":\"\"}"); } - el_val_t safe_text = json_safe(text); + el_val_t safe_text = json_safe(final_text); return 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}")); return 0; } @@ -202,12 +299,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_19 = 0; if (str_eq(message, EL_STR(""))) { _if_result_19 = (transcript); } else { _if_result_19 = (message); } _if_result_19; }); + el_val_t eff_message = ({ el_val_t _if_result_30 = 0; if (str_eq(message, EL_STR(""))) { _if_result_30 = (transcript); } else { _if_result_30 = (message); } _if_result_30; }); 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_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_31 = 0; if (str_eq(req_model, EL_STR(""))) { _if_result_31 = (chat_default_model()); } else { _if_result_31 = (req_model); } _if_result_31; }); 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) { @@ -222,7 +319,7 @@ el_val_t handle_chat_as_soul(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_21 = 0; if (str_eq(reply, EL_STR(""))) { _if_result_21 = (json_get(resp, EL_STR("reply"))); } else { _if_result_21 = (reply); } _if_result_21; }); + el_val_t reply2 = ({ el_val_t _if_result_32 = 0; if (str_eq(reply, EL_STR(""))) { _if_result_32 = (json_get(resp, EL_STR("reply"))); } else { _if_result_32 = (reply); } _if_result_32; }); if (str_eq(message, EL_STR(""))) { return EL_STR(""); } diff --git a/dist/chat.elh b/dist/chat.elh index cf0dd77..5327ec2 100644 --- a/dist/chat.elh +++ b/dist/chat.elh @@ -9,6 +9,9 @@ extern fn clean_llm_response(s: String) -> String extern fn handle_chat(body: String) -> String extern fn handle_see(body: String) -> String extern fn studio_tools_json() -> String +extern fn agentic_api_key() -> String +extern fn agentic_tools_literal() -> String +extern fn dispatch_tool(tool_name: String, tool_input: String) -> String extern fn handle_chat_agentic(body: String) -> String extern fn handle_chat_as_soul(body: String) -> String extern fn auto_persist(req: String, resp: String) -> Void diff --git a/dist/elp-input.c b/dist/elp-input.c index bfe43b3..2a9f7b4 100644 --- a/dist/elp-input.c +++ b/dist/elp-input.c @@ -87,14 +87,28 @@ el_val_t handle_elp_chat(el_val_t body) { fi = (fi + 1); } el_val_t frame_nodes = ({ el_val_t _if_result_13 = 0; if (str_eq(kept_json, EL_STR(""))) { _if_result_13 = (EL_STR("[]")); } else { _if_result_13 = (el_str_concat(el_str_concat(EL_STR("["), kept_json), EL_STR("]"))); } _if_result_13; }); - el_val_t top_node = json_array_get(frame_nodes, 0); + el_val_t fn_total = json_array_len(frame_nodes); + el_val_t fn_i = 0; + el_val_t topic_lower = str_to_lower(topic); + el_val_t found_node = EL_STR(""); + while (fn_i < fn_total) { + el_val_t candidate = json_array_get(frame_nodes, fn_i); + el_val_t cand_content = json_get(candidate, EL_STR("content")); + el_val_t cand_lower = str_to_lower(cand_content); + el_val_t matches = str_contains(cand_lower, topic_lower); + if (matches && str_eq(found_node, EL_STR(""))) { + found_node = candidate; + } + fn_i = (fn_i + 1); + } + el_val_t top_node = ({ el_val_t _if_result_14 = 0; if (str_eq(found_node, EL_STR(""))) { _if_result_14 = (json_array_get(frame_nodes, 0)); } else { _if_result_14 = (found_node); } _if_result_14; }); el_val_t top_raw = json_get(top_node, EL_STR("content")); - el_val_t patient_raw = ({ el_val_t _if_result_14 = 0; if (str_eq(top_raw, EL_STR(""))) { _if_result_14 = (topic); } else { _if_result_14 = (({ el_val_t _if_result_15 = 0; if ((str_len(top_raw) > 200)) { _if_result_15 = (str_slice(top_raw, 0, 200)); } else { _if_result_15 = (top_raw); } _if_result_15; })); } _if_result_14; }); + el_val_t patient_raw = ({ el_val_t _if_result_15 = 0; if (str_eq(top_raw, EL_STR(""))) { _if_result_15 = (topic); } else { _if_result_15 = (({ el_val_t _if_result_16 = 0; if ((str_len(top_raw) > 200)) { _if_result_16 = (str_slice(top_raw, 0, 200)); } else { _if_result_16 = (top_raw); } _if_result_16; })); } _if_result_15; }); el_val_t patient_safe = str_replace(str_replace(patient_raw, EL_STR("\""), EL_STR("'")), EL_STR("\n"), EL_STR(" ")); - el_val_t intent_val = ({ el_val_t _if_result_16 = 0; if (str_eq(predicate, EL_STR("store"))) { _if_result_16 = (EL_STR("command")); } else { _if_result_16 = (EL_STR("assert")); } _if_result_16; }); + el_val_t intent_val = ({ el_val_t _if_result_17 = 0; if (str_eq(predicate, EL_STR("store"))) { _if_result_17 = (EL_STR("command")); } else { _if_result_17 = (EL_STR("assert")); } _if_result_17; }); el_val_t gen_form = 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("{\"intent\":\""), intent_val), EL_STR("\"")), EL_STR(",\"agent\":\"I\"")), EL_STR(",\"predicate\":\"")), predicate), EL_STR("\"")), EL_STR(",\"patient\":\"")), patient_safe), EL_STR("\"")), EL_STR(",\"tense\":\"present\",\"aspect\":\"simple\",\"lang\":\"en\"}")); el_val_t realized = generate(gen_form); - el_val_t response = ({ el_val_t _if_result_17 = 0; if (str_eq(realized, EL_STR(""))) { _if_result_17 = (({ el_val_t _if_result_18 = 0; if (str_eq(patient_safe, EL_STR(""))) { _if_result_18 = (EL_STR("Nothing in the engram matched that query.")); } else { _if_result_18 = (patient_safe); } _if_result_18; })); } else { _if_result_17 = (realized); } _if_result_17; }); + el_val_t response = ({ el_val_t _if_result_18 = 0; if (str_eq(realized, EL_STR(""))) { _if_result_18 = (({ el_val_t _if_result_19 = 0; if (str_eq(patient_safe, EL_STR(""))) { _if_result_19 = (EL_STR("Nothing in the engram matched that query.")); } else { _if_result_19 = (patient_safe); } _if_result_19; })); } else { _if_result_18 = (realized); } _if_result_18; }); el_val_t safe_resp = str_replace(str_replace(response, EL_STR("\""), EL_STR("'")), EL_STR("\r"), EL_STR("")); return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"response\":\""), safe_resp), EL_STR("\",\"model\":\"elp-native\",\"frame\":")), frame), EL_STR(",\"nodes\":")), frame_nodes), EL_STR("}")); return 0; diff --git a/dist/neuron b/dist/neuron index b0f25c5..c5da98a 100755 Binary files a/dist/neuron and b/dist/neuron differ diff --git a/dist/routes.c b/dist/routes.c index f0cbda3..4f71bd7 100644 --- a/dist/routes.c +++ b/dist/routes.c @@ -33,6 +33,9 @@ el_val_t clean_llm_response(el_val_t s); el_val_t handle_chat(el_val_t body); 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 dispatch_tool(el_val_t tool_name, el_val_t tool_input); el_val_t handle_chat_agentic(el_val_t body); el_val_t handle_chat_as_soul(el_val_t body); el_val_t auto_persist(el_val_t req, el_val_t resp); diff --git a/dist/soul.c b/dist/soul.c index 475786c..141b1cf 100644 --- a/dist/soul.c +++ b/dist/soul.c @@ -39,6 +39,9 @@ el_val_t clean_llm_response(el_val_t s); el_val_t handle_chat(el_val_t body); 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 dispatch_tool(el_val_t tool_name, el_val_t tool_input); el_val_t handle_chat_agentic(el_val_t body); el_val_t handle_chat_as_soul(el_val_t body); el_val_t auto_persist(el_val_t req, el_val_t resp); diff --git a/dist/studio.c b/dist/studio.c index 5e27a23..fdd51f9 100644 --- a/dist/studio.c +++ b/dist/studio.c @@ -30,6 +30,9 @@ el_val_t clean_llm_response(el_val_t s); el_val_t handle_chat(el_val_t body); 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 dispatch_tool(el_val_t tool_name, el_val_t tool_input); el_val_t handle_chat_agentic(el_val_t body); el_val_t handle_chat_as_soul(el_val_t body); el_val_t auto_persist(el_val_t req, el_val_t resp);