Add Matrix NL-query Q&A surface (W2 step 5)
Read-only natural-language query over the curated nl_query endpoint, answered in-thread. Two entry points (room-per-purpose model): a dedicated Q&A room (MATRIX_QUERY_ROOM) where every top-level message is a question, plus the ?/@bot trigger in the intake room as a cross-room convenience. Both routes hit the same handle_query -> crm_client.nl_query -> POST /api/query/nl; translation runs on the box's local model, nothing leaves the box, and there is no write path so no approval gate applies. Pure logic (trigger parsing, answer rendering) in query.py with offline tests; async room wiring in bot.py (live-smoke only, per the bot's convention). Bot-side only, ships on the Spark via git pull + restart. Depends on the box-side /api/query/nl endpoint, which lands with the v93 s9pk (reminders + W2): until v93 is installed the Q&A surface 404s, so the bot deploy is staged to follow that install.
This commit is contained in:
@@ -113,6 +113,41 @@ def test_match_no_query_skips_network():
|
||||
assert res == {"match": None, "candidates": []}
|
||||
|
||||
|
||||
def test_nl_query_returns_endpoint_data():
|
||||
cap = {}
|
||||
orig = _with_stub_authed(
|
||||
(200, {"data": {"intent": "top_investors_committed", "rows": [], "summary": "ok"}}), cap)
|
||||
try:
|
||||
res = crm_client.nl_query("top investors")
|
||||
finally:
|
||||
crm_client._authed = orig
|
||||
assert res["intent"] == "top_investors_committed"
|
||||
assert cap["path"] == "/api/query/nl"
|
||||
|
||||
|
||||
def test_nl_query_passes_through_soft_503():
|
||||
# Model-down still carries a structured body (the endpoint 503s with the error in `data`) —
|
||||
# return it for the renderer to surface, don't raise.
|
||||
orig = _with_stub_authed((503, {"data": {"error": "model_unavailable"}}))
|
||||
try:
|
||||
res = crm_client.nl_query("anything")
|
||||
finally:
|
||||
crm_client._authed = orig
|
||||
assert res["error"] == "model_unavailable"
|
||||
|
||||
|
||||
def test_nl_query_raises_on_auth_failure():
|
||||
orig = _with_stub_authed((403, {"error": "Bot or admin required"}))
|
||||
raised = False
|
||||
try:
|
||||
crm_client.nl_query("x")
|
||||
except RuntimeError:
|
||||
raised = True
|
||||
finally:
|
||||
crm_client._authed = orig
|
||||
assert raised
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
fns = [v for k, v in sorted(globals().items()) if k.startswith("test_") and callable(v)]
|
||||
for fn in fns:
|
||||
|
||||
Reference in New Issue
Block a user