feat(chatbot): add in-page-nav attribute for cauldron testing - #149
feat(chatbot): add in-page-nav attribute for cauldron testing#149yodem wants to merge 2 commits into
Conversation
Adds in-page-nav boolean attribute that forces sefaria:bootstrap-url dispatch for all Sefaria links even when the host page is not on sefaria.org. Set this on cauldron/staging embeds to test topic and source in-page navigation without a production deployment. Do not deploy to production. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
The preview deployment for sefaria/ai-chatbot:server is ready. 🟢 Open app | Open Build Logs | Open Application Logs Last updated at: 2026-06-03 16:21:07 CET |
|
I'll analyze this PR systematically, reviewing the code changes, architecture, test coverage, and quality. PR OverviewThis PR implements a "Topic Appetizer" feature — a parallel pipeline that shows relevant Sefaria topic links within 5-8 seconds while the main AI agent processes the user's query. It also adds a "Progress Trail" component that shows streaming tool call progress. Key Changes
Issues Found🔴 Critical Issues1. Hardcoded Secret in Load Test Script CHATBOT_USER_TOKEN_SECRET=Mg57y8NKXyaZCQHFbFvXECUEoWhjGoUXJbbVt3H
USER_ID="cLmwgp3ikvK5B0883-1U6JIhm1ZkQFTuiX19h0PGzRdqfuo9rYCuSd9Fob6oG7Yx5tA4fuhH6SZ18PaE1S13-u8DD0oK7sZfn96Zo8INN0PI8Bfhxco4bA2d66dEJ8ePTCp2NMkbmrRd9Dny9sijiY-eKOAJcDZlNb4JPaSHlO2t9ckKbdn_IhQqPboINA=="A secret key and what appears to be an encrypted user token are hardcoded in the script. Even if this is a test/staging secret, it should not be committed to source control. The comment says "Requires: CHATBOT_USER_TOKEN_SECRET" as an env var, but then hardcodes it anyway. 2. XSS Risk in function linkifyRefs(text) {
const escaped = text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
// ...
return escaped.replace(/(['"])([^'"]+)\1/g, (match, quote, ref) => {
const url = refToUrl(ref);
if (!url) return match;
return `${quote}${icon}<a class="trail-ref-link" href="${url}" ...>${ref}</a>${quote}`;
});
}The Actually, looking more carefully: the outer 3. result = asyncio.run(appetizer_service.find_appetizer(data["text"]))Using 🟡 Medium Issues4. stream_closed = False
# ...
def run_appetizer():
if result and not stream_closed:
progress_queue.put(update, timeout=0.5)
5. Appetizer Executor Not Awaited on Error Paths executor.shutdown(wait=False)
appetizer_executor.shutdown(wait=False)The 6. Inconsistent Timeout Exception Handling except TimeoutError:Should be 7. Playwright MCP Snapshot Files Committed 8. Duplicate PNG Files 9. tool_input=tool_input,
10. function normalizeAppetizerData(raw) {
if (!raw) return null;
if (raw.topics) return raw;
return { topics: [{ topicSlug: raw.topicSlug, topicTitle: raw.topicTitle, topicUrl: raw.topicUrl }] };
}This shim handles old single-topic format. If this is for backward compatibility with persisted messages, it's fine. But it suggests the data model changed mid-development without a clean migration. Consider documenting when this shim can be removed. 🟢 Minor Issues11. 12. Looking at the component more carefully — the header is a 13. Plan Documents in 14. user-id="VrEKrbLVo8iV0AgQDGNStkXu0fWsD08bM7iYQ2AwZKRkiTrPuoBxYTPWumaIdMLw_..."An encrypted user token is committed to Test CoverageThe test file
Coverage estimate: ~85% of the new backend code is tested. The The test for Architecture AssessmentThe two-tier approach (direct API → LLM fallback) from the plan was replaced with a single LLM-first approach using Sonnet (not Haiku) with tool-forcing. This is a significant architectural change from the plan:
This is actually a better design for quality but uses a more expensive model (Sonnet vs Haiku). The 8-second timeout (vs 5-second in the plan) reflects this tradeoff. The parallel thread architecture is sound. The SummaryThis is a well-executed feature with good test coverage on the backend. The main concerns are:
Code Quality ScoreSub-scores: S (Scope) = 16/20
A (Architecture) = 15/20
I (Implementation) = 14/20
R (Risk) = 10/20
Q (Quality) = 11/15
P (Performance/Security) = 2/5
Base Score = 16 + 15 + 14 + 10 + 11 + 2 = 68 Effort Scale:
Final Score: 68 × 1.0 = 68 Code Quality Data (JSON){
"_schema": "code_quality_v5",
"total_score": 68,
"total_factors": "68 × 1.0 (Extra Large ESF) = 68",
"scope_score": 16,
"scope_factors": "8+ files across frontend/backend/config; new SSE event type; parallel thread architecture; new UI components; cross-cutting frontend-backend-external API integration; analytics event dispatch",
"architecture_score": 15,
"architecture_factors": "New parallel appetizer thread pattern; new component hierarchy (TopicAppetizer, ProgressTrail, SourceSuggestion); SSE protocol extension; slug fallback in search_topics; progress trail replaces single-bubble thinking indicator; tool-forcing pattern for structured LLM output",
"implementation_score": 14,
"implementation_factors": "asyncio.wait_for timeout wrapping; multi-candidate LLM extraction with deduplication; tool-forcing for structured output; linkifyRefs regex ref detection; findLastIndex for correct tool_end matching; normalizeAppetizerData backward compat shim; in-page navigation logic with hostname checks",
"risk_score": 10,
"risk_factors": "New parallel thread adds concurrency complexity (+3); hardcoded secrets in committed files (+4); no feature flag for appetizer (+2); tool_input exposure in tool_end events (+2); stream_closed race condition (+1); SSE protocol extension is backward compatible (-2)",
"quality_score": 11,
"quality_factors": "Good backend test coverage ~85% of new service code (+4); edge case tests: deduplication, partial hits, timeout, Hebrew (+3); feature-tests.json as integration record (+2); plan documents provide context (+1); no frontend |
Adds a "reading now" context chip at the top of the chat that displays the Sefaria text ref currently open in the reader. Clicking it navigates back to that ref via sefaria:bootstrap-url. Also removes version_language from the get_text tool description to clean up thinking step labels. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
in-page-navboolean attribute to<lc-chatbot>that forcessefaria:bootstrap-urldispatch for all Sefaria links, even when the host page is not onsefaria.orgUsage
Add
in-page-nav="true"to the chatbot embed in the Sefaria-Project cauldron branch:This branch is for cauldron testing only. The
in-page-navattribute bypasses the production hostname guard. Delete after testing.🤖 Generated with Claude Code