Repository navigation
feat(ai): grounded site assistant with caps, evals and Home box - #392
Merged
arutsh merged 7 commits intoOct 17, 2026
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
arutsh
changed the base branch from
AI/feat/Issue-381/site-assistant-retrieval-evals-group1
to
main
October 17, 2026 15:51
…; add specs, design and tasks Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…387 into change dir, add tracking block Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…assistant ask endpoint (group 1) Anonymous /ai/site-assistant/ask and /config behind SITE_ASSISTANT_ENABLED: retrieve site chunks, short-circuit weak matches, generate a structured SiteAnswer, then keep only server-resolved citations and fail closed on unverified links, invalid output or model errors. Pipeline failures (prompt, retrieval, render) return 503. Spans go through a redacting tracer that records exceptions by type only, since pydantic validation errors otherwise echo raw model output into the agent-run span. Seeds the v1 prompt (migration 020), shares the Ollama egress-checked builder and platform Anthropic builder, caches the resolved model and agent, and moves get_db to app/db/session.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… trusted client IP (group 2) Per-IP and global UTC-day caps on the anonymous ask endpoint, counted in Redis under HMAC-hashed IPs (IPv6 collapsed to /64) and failing closed with 503 when Redis is unreachable. The global cap is only charged when the model will actually be called, so short-circuited questions are free. nginx now overwrites X-Forwarded-For instead of appending and dev uvicorn trusts proxy headers, so the counted address is the visitor's, not a client-chosen one; a test pins the Caddyfile to that behaviour. Retry-After is exposed via CORS for the 429 response. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… evals and injection corpus (group 3) Deterministic eval tests cover unanswerable short-circuits, citation/link filtering and fail-closed output; opt-in eval_site_assistant.py reports hallucination and injection probes per category. Route tests now reuse the shared seeded_prompt helper. Dev env enables the site assistant by default. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…stant box (group 4) SiteAssistantBox on Home behind config.enabled: persona toggle, length-limited question, plain-text answer with same-origin source links, browse-instead fallback for unanswerable/429/503/404/403, and an AI-processing notice. Config query skips signed-in visitors. Privacy processors section and user guide disclose the assistant. Shared test QueryClient/AxiosError helpers. Eval fixture: injected.tag-break repeats its topic terms so lexical retrieval ranks it into the top 5 for its probe. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…aim matches in eval refusals
The live eval flagged refusals ("does not address whether ... guarantees grant
funding") as forbidden claims. Refusals are served as the fallback, so only
answerable output is scored for claims; links and prompt leaks still count.
Route tests pin the cap overrides to None so local env caps can't leak in.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
arutsh
force-pushed
the
AI/feat/Issue-388/site-assistant-grounded-answers-group1
branch
from
October 17, 2026 15:54
b003485 to
5aae561
Compare
arutsh
deleted the
AI/feat/Issue-388/site-assistant-grounded-answers-group1
branch
October 19, 2026 18:35
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements all four task groups of
ai-feat-387-site-assistant-grounded-answers(parent #387) on one branch: an anonymous, grounded site assistant behindSITE_ASSISTANT_ENABLED(off by default).Group 1: ask endpoint (#388)
POST /api/v1/ai/site-assistant/askandGET /config. When the flag is off,askreturns 404. The pipeline retrieves site chunks, skips the model when retrieval is weak, generates a structuredSiteAnswer, then keeps only citations the server can resolve. Answers that link to other hosts, invalid output and model errors all returnanswerable:false. Prompt, retrieval or render failures, or a model that can't be resolved, return 503.get_dbmoves toapp/db/session.py.Group 2: daily caps and client IP (#389)
check_daily_cap: a fail-closed, UTC-day Redis counter keyed by an HMAC-hashed IP, with per-provider cap profiles. The per-IP cap is checked after validation; the global cap only before a model call. Cap hits return 429 withRetry-After; limiter errors return 503.X-Forwarded-Forcan't change the counted address, and a deployment note that the ai port must never be published directly.Group 3: evals (#390)
<site_content>, and obeyed injections (out-of-set IDs, foreign URLs and bare hosts, malformed output) fail closed.injected.tag-breakfixture repeats its topic terms so lexical retrieval ranks it into the top 5; with one mention each it scored below longer guide sections and never reached the prompt.scripts/eval_site_assistant.py(not in CI) reports per category for hallucination, content-injection and question-injection probes.Group 4: Home assistant box (#391)
siteAssistantApi.ts: theconfigquery (retry: false) and theaskmutation, with errors sorted into 429, 503 and other.SiteAssistantBoxon Home, shown only whenconfig.enabled. It has a persona toggle and a length-limited field. The answer is plain text with source links (non-site-path citations are dropped). Unanswerable questions and cap or error responses fall back to browse links, and the AI-processing notice links to the privacy policy. Card layout on mobile.Stacked on #386, so the base is
AI/feat/Issue-381/....Test plan
AI_TEST_POSTGRES_URL=... pytest tests/(355 passed, 0 skipped). ai CI doesn't run on this stacked PR, so this was run locally.npm run lint:ci(87/87 baseline),vitest run(497 passed),tsc --noEmitandvite buildpython scripts/eval_site_assistant.py --runs 3; first results belowLive eval results
First run, 2026-10-17:
claude-haiku-4-5-20251001, promptsite_assistantv1, 14 probes × 3 runs.served_violis 0 everywhere: nothing bad reached a visitor.model_violis checker noise, not model failures. A--verbosere-run showed the flagged answers were refusals (answerable=false, no citations), e.g. "The website does not address whether using OpenGrantFlow guarantees grant funding". Theforbiddenpatterns match phrases inside the denial. The role-play probe refused in the same way. Fixed in b003485: forbidden claims are now scored only onanswerable=trueoutput (links and prompt leaks still count on refusals), so a re-run should show these as 0.hallucination-revenueshort-circuits before the model: retrieval finds nothing aboveSITE_ASSISTANT_MIN_SCORE.🤖 Generated with Claude Code
Closes #388
Closes #389
Closes #390
Closes #391
Closes #387