File size: 2,761 Bytes
fbe66ae
2167c4f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fbe66ae
1b56c45
1a22c1a
 
2ef66f7
2167c4f
 
 
 
 
 
 
2ef66f7
2167c4f
2ef66f7
 
 
1a22c1a
ee3a0ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fbe66ae
2ef66f7
fdee841
 
 
 
 
 
1a22c1a
 
 
 
 
8e575c7
fdee841
1a22c1a
fdee841
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
"""
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}