| """ |
| LibBee /agent endpoint - thin FastAPI router. |
| |
| The pipeline itself lives in ``src/agentcore`` split by stage: |
| |
| models.py Stage 0 Pydantic I/O contracts |
| constants.py regexes, URLs, prompts (no logic) |
| utils.py shared helpers, LLM factory, URL builders |
| classify.py Stage 2-3 rule pre-classifier + LLM intent classifier |
| libcal.py live hours/events via Cloudflare Worker proxy |
| scholarly.py Semantic Scholar / OpenAlex / Crossref / Unpaywall |
| rendering.py HTML fragments (badges, trace, AI-tools footer) |
| intents_library.py Stage 4 library_info handlers |
| intents_search.py Stage 4 search_academic / search_medical machinery |
| intents_general.py Stage 4 general / social handlers |
| orchestrator.py Stage 1+4 injection gate, routing pipeline, D1 logging |
| |
| This file only wires HTTP to the orchestrator. |
| """ |
| import time |
|
|
| from fastapi import APIRouter, Request |
|
|
| from src.agentcore.models import AgentRequest, AgentResponse |
| from src.agentcore.orchestrator import _agent_query_inner, _log_agent_query |
| from src.agentcore.utils import ( |
| _get_runtime_config, |
| _normalize_whitespace, |
| _safe_metrics_increment, |
| _sanitize_llm_response, |
| ) |
| from src.services.staff_service import STAFF_DIRECTORY |
|
|
| router = APIRouter() |
|
|
|
|
| @router.post("", response_model=AgentResponse) |
| async def agent_query(request: Request, req: AgentRequest): |
| start_time = time.time() |
| question = _normalize_whitespace(req.question) |
| history = req.history |
| model = req.model |
| client_state = req.client_state |
| _safe_metrics_increment("agent_requests") |
| response = await _agent_query_inner(question, history, model, client_state, start_time) |
| response.answer = _sanitize_llm_response(response.answer) |
| _log_agent_query(question, response, start_time) |
| _rcfg = _get_runtime_config() |
| _ann = _rcfg.get("announcement", "").strip() |
| if _ann and response.intent not in ("social_greeting", "social"): |
| _ann_html = ( |
| '<div style="margin-top:14px;padding:10px 14px;border-radius:10px;' |
| 'background:#fffbeb;border:1px solid #fde68a;font-size:.82rem;color:#92400e">' |
| f'📢 {_ann}</div>' |
| ) |
| response.answer = response.answer + _ann_html |
| return response |
|
|
|
|
| @router.get("/test") |
| async def test(): |
| return { |
| "status": "ok", |
| "message": "Agent endpoint is working!", |
| "staff_loaded": len(STAFF_DIRECTORY), |
| } |
|
|
|
|
| @router.get("/rag-status") |
| async def rag_status(): |
| try: |
| from app import get_rag_service |
| return get_rag_service().get_stats() |
| except Exception as e: |
| return {"error": str(e), "ready": False} |
|
|