fix(chat): wire agentic_tools_all into both agentic loop entry points #19
Reference in New Issue
Block a user
Delete Branch "fix/agentic-tools-all"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
In
handle_chat_agentic,tools_jsonwas set toagentic_tools_with_web()which includes built-in tools and web_search but not MCP connector tools. Users in agentic mode could never call anymcp__*tool even whenneuron-connectdis running.handle_dharma_room_turn_agentichad the same problem (agentic_tools_literal()) plus an inline copy of the 8-iteration agentic loop that lacked bridge suspension support.Changes
handle_chat_agentic(line 579):agentic_tools_with_web()→agentic_tools_all()handle_dharma_room_turn_agentic:agentic_tools_literal()→agentic_tools_all(), inline loop replaced withagentic_loop()call,room_idextracted from body for dharma-scoped session IDs (dharma:<room_id>) so bridge suspension works per-roomagentic_tools_all()callsconnector_tools_json()internally, which returns[]ifneuron-connectdis not running, so this is safe when the bridge is down.Test plan
mcp__neuron__*tools are available in agentic chat when neuron-connectd is runningReview: fix(chat): wire agentic_tools_all into both agentic loop entry points
The core goal is correct and the refactor of
handle_dharma_room_turn_agenticto delegate toagentic_loopis a genuine improvement — the old inline loop calleddispatch_toolfor any tool without theis_builtin_toolguard, so MCP connector tools would have been misrouted. Delegating toagentic_loopfixes that silently.One issue needs attention before merge:
Missing tool_pending propagation (warning)
handle_dharma_room_turn_agenticnow delegates toagentic_loop, which can return either a final reply or a bridge-suspension envelope ({"tool_pending":true,...}). The new code only checks for"error"and then reads"reply":When a connector tool suspends the loop,
json_get(loop_result, "reply")returns""(the key doesn't exist in the pending envelope), so the function returns{"response":"","cgi_id":"...","tools_used":[]}. The old inline loop had an explicit empty-text guard that returned an error; that guard was dropped in the refactor.The fix is to detect and pass through the pending envelope, then restore the empty-reply guard:
Note:
handle_chat_agentichas the same gap (also introduced in this PR for the tool_pending case), though in practice the Studio client may never send a dharma-agentic request that hits an MCP bridge tool today. The issue is latent but will surface as soon as connector tools are actively used.Minor notes
agentic_tools_all()makes a live 2-second curl call to the connector bridge on every invocation. For high-frequency dharma room turns this adds latency even when no connectors are configured. Worth caching in soul state with a short TTL eventually.room_idflows directly into a state key without sanitisation — low risk given the call chain, but worth a comment on expected format.What's good
handle_dharma_room_turn_agenticis a clear improvement in maintainability.room_id-namespaced session_id ("dharma:" + room_id) is the right approach for bridge suspension in rooms.agentic_tools_literal→agentic_tools_allin the dharma path correctly adds web search and connector tools, matchinghandle_chat_agentic."error"+"response"+"cgi_id") matches the existing dharma response contract.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)