M5: implement RAGcore knowledge integration

KnowledgeProvider protocol with a deterministic TF-IDF-weighted extractive demo provider (never generative, always cites real excerpts) and a RAGcore HTTP adapter that degrades cleanly to unavailable. Knowledge nav + chat-style Q&A UI with source cards and honest grounded/insufficient/unavailable states. 57 backend tests passing, ruff clean. Fixed a real relevance bug (generic terms like "vehicle" crowding out distinctive matches) via IDF weighting, found by testing the actual S6 scenario. Verified end-to-end in the browser: grounded damage question cites both expected procedures; unrelated question honestly returns insufficient evidence with no fabrication.
This commit is contained in:
NuklearRabbit
2026-08-01 22:57:06 +02:00
parent 59d663a43a
commit b511ba2dbc
14 changed files with 710 additions and 3 deletions
+27
View File
@@ -226,6 +226,33 @@ a { color: #1f5c8f; }
}
.data-table td button:disabled { opacity: 0.6; cursor: not-allowed; }
.knowledge-status { color: #607084; font-size: 0.9rem; margin-bottom: 16px; }
.knowledge-form { margin-bottom: 20px; }
.knowledge-input-row { display: flex; gap: 10px; flex-wrap: wrap; }
.knowledge-input-row input {
flex: 1; min-width: 240px; padding: 10px 12px; border: 1px solid #cfd8e2;
border-radius: 8px; font-size: 0.95rem;
}
.knowledge-input-row button {
padding: 10px 20px; border-radius: 8px; border: none;
background: #14324f; color: white; font-weight: 700; cursor: pointer;
}
.knowledge-input-row button:disabled { opacity: 0.6; cursor: not-allowed; }
.exchange-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 16px; }
.exchange-question { font-size: 1rem; margin: 0 0 6px; }
.evidence-state { display: inline-block; margin: 0 0 10px; padding: 3px 10px; border-radius: 999px; font-weight: 700; font-size: 0.8rem; }
.evidence-grounded { background: #e6f5ec; color: #1f6d3d; }
.evidence-insufficient { background: #fdf1de; color: #8a5a10; }
.evidence-unavailable { background: #fbe6e6; color: #8f2323; }
.source-cards { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.source-card { background: #f6f8fb; border: 1px solid #dce3eb; border-radius: 10px; padding: 12px; }
.source-title { margin: 0; font-weight: 700; }
.source-version { color: #607084; font-weight: 400; font-size: 0.85rem; }
.source-section { margin: 2px 0 6px; color: #375065; font-size: 0.85rem; font-weight: 600; }
.source-excerpt { margin: 0; font-size: 0.88rem; color: #47566b; }
@media (max-width: 700px) {
.app-header { flex-direction: column; align-items: flex-start; }
.user-badge { margin-left: 0; }