fix/test(chat): guard handle_dharma_room_turn_agentic against tool_pending and empty reply
Neuron Soul CI / build (pull_request) Failing after 8m0s
Neuron Soul CI / build (pull_request) Failing after 8m0s
When agentic_loop suspends for an MCP bridge tool it returns a
{"tool_pending":true,...} envelope with no "reply" key. Without an
explicit check, json_get(loop_result, "reply") returns "" and the
function emitted {"response":"","cgi_id":"..."} — a silent empty
response indistinguishable from a successful LLM turn with no content.
Two guards added after the existing error check:
1. tool_pending passthrough: if the loop suspended, return the pending
envelope directly so callers (dharma room orchestrators) can
distinguish suspension from failure and route to the approve flow.
2. Empty-reply guard: if final_text is empty after the pending check,
return an explicit {"error":"no response",...} envelope instead of
silently succeeding with an empty response field.
Also adds tests/test_agentic_tools.el:
- agentic_tools_all() includes all literal tool names and web_search
- connector_tools_json() returns valid JSON when bridge is down (graceful degradation)
- tool_pending envelope detection patterns (the is_pending logic)
- json_get(pending_envelope, "reply") returns "" confirming the empty-reply
guard is load-bearing (pure string/JSON, no LLM or network required)
This commit is contained in:
@@ -993,7 +993,21 @@ fn handle_dharma_room_turn_agentic(body: String) -> String {
|
||||
return "{\"error\":\"" + result_error + "\",\"response\":\"\",\"cgi_id\":\"" + cgi_id + "\"}"
|
||||
}
|
||||
|
||||
// If agentic_loop suspended for an MCP bridge tool, pass the pending envelope
|
||||
// straight through so callers can distinguish suspension from failure.
|
||||
// A silent empty response is indistinguishable from an LLM error to any caller.
|
||||
let is_pending: Bool = str_eq(json_get(loop_result, "tool_pending"), "true")
|
||||
|| str_starts_with(loop_result, "{\"tool_pending\":true")
|
||||
if is_pending {
|
||||
return loop_result
|
||||
}
|
||||
|
||||
let final_text: String = json_get(loop_result, "reply")
|
||||
// Guard against a silent empty response - produce an explicit error so callers
|
||||
// cannot mistake a failed turn for a successful one with empty content.
|
||||
if str_eq(final_text, "") {
|
||||
return "{\"error\":\"no response\",\"response\":\"\",\"cgi_id\":\"" + cgi_id + "\"}"
|
||||
}
|
||||
let tools_arr: String = json_get_raw(loop_result, "tools_used")
|
||||
let eff_tools: String = if str_eq(tools_arr, "") { "[]" } else { tools_arr }
|
||||
let safe_text: String = json_safe(final_text)
|
||||
|
||||
Reference in New Issue
Block a user