Spaces:
Running
Running
File size: 5,373 Bytes
f7db1cd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | """End-to-end test of Agent Chat: tools + RAG, with and without OpenRouter.
Covers:
1. LanceDB index is built from the live HF dataset
2. Tool executors work standalone (no LLM)
3. Agentic flow (OpenRouter) — LLM calls search_records / get_records_by_date_range
4. Fallback flow (OpenRouter disabled) — one-shot RAG via HF/no-op
Run: python -m scripts.test_agent_chat
"""
from __future__ import annotations
import json
import logging
import os
import sys
from pathlib import Path
_PROJECT_ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(_PROJECT_ROOT))
from dotenv import load_dotenv
load_dotenv(_PROJECT_ROOT / ".env")
logging.basicConfig(level=logging.WARNING, format="%(levelname)s: %(message)s")
CHIKU_PET_ID = "ec8ed3df-3b7b-4013-8d6d-c76832e1ec88"
SEP = "=" * 70
def _ok(cond: bool, label: str, detail: str = "") -> None:
tag = "PASS" if cond else "FAIL"
print(f" [{tag}] {label}" + (f" — {detail}" if detail else ""))
def step_1_build_index() -> None:
print(SEP)
print("STEP 1: pull latest HF dataset + rebuild LanceDB index")
print(SEP)
from guardiantails.services.hf_sync import download_backup
from guardiantails.models import init_db, get_db
from guardiantails.services.lance_service import rebuild_from_sqlite
download_backup()
init_db()
with get_db() as conn:
result = rebuild_from_sqlite(conn, pet_id=None)
_ok(result.get("status") == "ok", "index rebuild", str(result))
assert result.get("documents", 0) > 0, "no documents indexed — expected >0"
print()
def step_2_tool_executors() -> None:
print(SEP)
print("STEP 2: tool executors (no LLM)")
print(SEP)
from guardiantails.core.rag_chat import (
_tool_search_records,
_tool_date_range,
)
# 2a. search_records
r = json.loads(_tool_search_records(
CHIKU_PET_ID,
{"query": "seizure", "record_type": "seizure", "top_k": 5},
))
_ok(isinstance(r, list) and len(r) > 0, "search_records returns seizures", f"got {len(r)}")
if r:
first = r[0]
_ok(first.get("record_type") == "seizure", "first result is a seizure")
# 2b. date-range: doses in 48h before the Apr 10 seizure
r = json.loads(_tool_date_range(
CHIKU_PET_ID,
{"start_date": "2026-04-08", "end_date": "2026-04-10", "record_type": "dose"},
))
doses_in_window = [x for x in r if x.get("record_type") == "dose"]
missed = [x for x in doses_in_window if "Missed" in (x.get("summary") or "")]
_ok(len(doses_in_window) > 0, "date-range returns doses",
f"total={len(doses_in_window)}, missed={len(missed)}")
# 2c. date-range unfiltered — should cover multiple types
r = json.loads(_tool_date_range(
CHIKU_PET_ID,
{"start_date": "2026-04-08", "end_date": "2026-04-10"},
))
types_found = {x.get("record_type") for x in r}
_ok(len(types_found) >= 2, "date-range spans multiple record types",
f"types={types_found}")
print()
def step_3_agentic_flow() -> None:
print(SEP)
print("STEP 3: agentic flow via OpenRouter (should emit tool_calls)")
print(SEP)
if not os.getenv("OPENROUTER_API_KEY"):
print(" [SKIP] OPENROUTER_API_KEY not set")
return
from guardiantails.models import get_db
from guardiantails.core.rag_chat import rag_query
question = (
"Were there any missed or delayed medication doses in the 48 hours before "
"Chiku's April 10 2026 seizure? Use the tools to check."
)
with get_db() as conn:
out = rag_query(conn, CHIKU_PET_ID, question)
trace = out.get("trace", [])
tool_names = [t.get("name") for t in trace]
_ok(len(trace) > 0, "LLM invoked at least one tool", f"calls={tool_names}")
_ok(len(out.get("response", "")) > 50, "got a substantive response",
f"len={len(out.get('response',''))}")
_ok(len(out.get("sources", [])) > 0, "sources collected from tool calls",
f"count={len(out.get('sources', []))}")
print()
print(" --- RESPONSE (truncated) ---")
print(" " + (out.get("response") or "")[:600].replace("\n", "\n "))
print()
def step_4_fallback_flow() -> None:
print(SEP)
print("STEP 4: fallback (OpenRouter disabled) — one-shot RAG")
print(SEP)
# Temporarily strip the key and reload settings
saved = os.environ.pop("OPENROUTER_API_KEY", None)
try:
from guardiantails.models import get_db
from guardiantails.core.rag_chat import rag_query
question = "Summarize Chiku's seizure history and any patterns."
with get_db() as conn:
out = rag_query(conn, CHIKU_PET_ID, question)
_ok(isinstance(out.get("response"), str),
"fallback returns a response string",
f"len={len(out.get('response','') or '')}")
_ok(len(out.get("sources", [])) > 0,
"fallback retrieved sources via one-shot RAG",
f"count={len(out.get('sources', []))}")
finally:
if saved is not None:
os.environ["OPENROUTER_API_KEY"] = saved
print()
def main() -> None:
step_1_build_index()
step_2_tool_executors()
step_3_agentic_flow()
step_4_fallback_flow()
print(SEP)
print("END-TO-END TEST COMPLETE")
print(SEP)
if __name__ == "__main__":
main()
|