diff --git a/chat.el b/chat.el index 930935c..201924f 100644 --- a/chat.el +++ b/chat.el @@ -2243,8 +2243,16 @@ fn agentic_loop(session_id: String, model: String, safe_sys: String, tools_json: } while keep_going && iteration < 8 { + // STOPGAP (2026-08-03, neuron#78 bug b / ADR 0005): the block walk below keeps + // only the FIRST tool_use block per round, so a PARALLEL tool_use response leaves + // the other ids without tool_result and the next turn 400s with + // "tool_use ids found without tool_result" — killing the run. Sending Anthropic's + // documented tool_choice.disable_parallel_tool_use makes the wire contract match + // what this loop can actually assemble. The real fix — a multi-tool_result loop + // that answers every block in a round — is Will's; see neuron#78. let req_body: String = "{\"model\":\"" + model + "\"" + ",\"max_tokens\":4096" + + ",\"tool_choice\":{\"type\":\"auto\",\"disable_parallel_tool_use\":true}" + ",\"system\":\"" + safe_sys + "\"" + ",\"tools\":" + tools_json + ",\"messages\":" + messages diff --git a/dist/soul.c b/dist/soul.c index 7c47185..1dbe516 100644 --- a/dist/soul.c +++ b/dist/soul.c @@ -28170,7 +28170,7 @@ el_val_t agentic_loop(el_val_t session_id, el_val_t model, el_val_t safe_sys, el state_set(el_str_concat(EL_STR("run_progress_"), session_id), EL_STR("")); } 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 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,\"tool_choice\":{\"type\":\"auto\",\"disable_parallel_tool_use\":true}")), 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) {