From 4309c02eb052c2573e2783fa76ec9c1550033863 Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 26 Jun 2026 21:01:58 +0800 Subject: [PATCH] fix(web): surface knowledge RAG asset gap --- apps/web/messages/en.json | 8 +++- apps/web/messages/zh-TW.json | 8 +++- .../src/app/[locale]/knowledge-base/page.tsx | 46 +++++++++++++++++-- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 2c24bfae..c86fc91a 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -1940,7 +1940,9 @@ "ownerQueueSub": "ready {ready} / blocked {blocked}", "writeback": "已寫回", "writebackSafe": "只讀回讀;讀取不寫入", - "writebackUnsafe": "偵測到讀取寫入風險" + "writebackUnsafe": "偵測到讀取寫入風險", + "ragIndex": "RAG 索引", + "ragIndexSub": "sources {sources};0 代表語意檢索尚未沉澱" } }, "overview": { @@ -1978,6 +1980,10 @@ "verifier": { "title": "Verifier 回寫", "detail": "已批准或完成驗證 {ready} 筆;待 負責人審查 {pending} 筆。" + }, + "rag": { + "title": "RAG / 向量索引", + "detail": "索引 chunks {ready};來源 {pending}。0 代表 KM 尚未進入語意檢索資產。" } } }, diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 2c24bfae..c86fc91a 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -1940,7 +1940,9 @@ "ownerQueueSub": "ready {ready} / blocked {blocked}", "writeback": "已寫回", "writebackSafe": "只讀回讀;讀取不寫入", - "writebackUnsafe": "偵測到讀取寫入風險" + "writebackUnsafe": "偵測到讀取寫入風險", + "ragIndex": "RAG 索引", + "ragIndexSub": "sources {sources};0 代表語意檢索尚未沉澱" } }, "overview": { @@ -1978,6 +1980,10 @@ "verifier": { "title": "Verifier 回寫", "detail": "已批准或完成驗證 {ready} 筆;待 負責人審查 {pending} 筆。" + }, + "rag": { + "title": "RAG / 向量索引", + "detail": "索引 chunks {ready};來源 {pending}。0 代表 KM 尚未進入語意檢索資產。" } } }, diff --git a/apps/web/src/app/[locale]/knowledge-base/page.tsx b/apps/web/src/app/[locale]/knowledge-base/page.tsx index c6e34b45..8c67606b 100644 --- a/apps/web/src/app/[locale]/knowledge-base/page.tsx +++ b/apps/web/src/app/[locale]/knowledge-base/page.tsx @@ -116,14 +116,20 @@ interface KnowledgeStaleOwnerReviewCompletionQueueResponse { batch_writes_allowed: boolean } +interface KnowledgeRagStatsResponse { + total_chunks?: number + sources?: number +} + interface KnowledgeGovernanceTelemetry { staleCandidates: KnowledgeStaleCandidatesResponse | null ownerReviews: KnowledgeStaleOwnerReviewInboxResponse | null burnDown: KnowledgeStaleOwnerReviewBurnDownResponse | null completionQueue: KnowledgeStaleOwnerReviewCompletionQueueResponse | null + ragStats: KnowledgeRagStatsResponse | null } -type AutomationAssetKey = 'km' | 'playbook' | 'script' | 'monitoring' | 'verifier' +type AutomationAssetKey = 'km' | 'playbook' | 'script' | 'monitoring' | 'verifier' | 'rag' // ============================================================================= // Category Config @@ -301,6 +307,7 @@ export default function KnowledgeBasePage({ ownerReviews: null, burnDown: null, completionQueue: null, + ragStats: null, }) const [governanceLoading, setGovernanceLoading] = useState(true) @@ -360,7 +367,7 @@ export default function KnowledgeBasePage({ setGovernanceLoading(true) try { const apiBase = process.env.NEXT_PUBLIC_API_URL ?? '' - const [staleCandidates, ownerReviews, burnDown, completionQueue] = await Promise.all([ + const [staleCandidates, ownerReviews, burnDown, completionQueue, ragStats] = await Promise.all([ fetch(`${apiBase}/api/v1/ai/governance/km-stale-candidates?project_id=awoooi&limit=5`) .then(res => res.ok ? res.json() : null) .catch(() => null), @@ -373,6 +380,9 @@ export default function KnowledgeBasePage({ fetch(`${apiBase}/api/v1/ai/governance/km-stale-owner-review-completion-queue?project_id=awoooi&status_bucket=all&limit=5`) .then(res => res.ok ? res.json() : null) .catch(() => null), + fetch(`${apiBase}/api/v1/knowledge/rag/stats`) + .then(res => res.ok ? res.json() : null) + .catch(() => null), ]) setGovernanceTelemetry({ @@ -380,6 +390,7 @@ export default function KnowledgeBasePage({ ownerReviews, burnDown, completionQueue, + ragStats, }) } catch (err) { console.error('Failed to fetch knowledge governance telemetry', err) @@ -615,6 +626,8 @@ export default function KnowledgeBasePage({ entry.status === 'approved' || hasTag(entry, ['human_approved', 'postmortem']), ) + const ragChunks = governanceTelemetry.ragStats?.total_chunks ?? 0 + const ragSources = governanceTelemetry.ragStats?.sources ?? 0 const ownerPending = governanceTelemetry.ownerReviews?.total ?? governanceTelemetry.completionQueue?.pending_count @@ -666,6 +679,16 @@ export default function KnowledgeBasePage({ pct: pct(verifierReady), tone: 'border-status-healthy/20 bg-status-healthy/10 text-status-healthy', }, + { + key: 'rag' as AutomationAssetKey, + icon: FileSearch, + ready: ragChunks, + pending: ragSources, + pct: ragChunks > 0 ? 100 : 0, + tone: ragChunks > 0 + ? 'border-status-healthy/20 bg-status-healthy/10 text-status-healthy' + : 'border-status-critical/25 bg-status-critical/10 text-status-critical', + }, ] as const }, [displayedEntries, governanceTelemetry]) @@ -686,6 +709,8 @@ export default function KnowledgeBasePage({ return t('assetLedger.asset.monitoring.detail', values) case 'verifier': return t('assetLedger.asset.verifier.detail', values) + case 'rag': + return t('assetLedger.asset.rag.detail', values) } }, [formatCount, t], @@ -809,6 +834,8 @@ export default function KnowledgeBasePage({ const thresholdText = governanceSummary.threshold === null ? '--' : `${governanceSummary.threshold}%` const staleTotalValue = governanceSummary.staleTotal === null ? '--' : formatCount(governanceSummary.staleTotal) const entriesToThreshold = governanceSummary.entriesToThreshold === null ? '--' : formatCount(governanceSummary.entriesToThreshold) + const ragChunks = governanceTelemetry.ragStats?.total_chunks ?? 0 + const ragSources = governanceTelemetry.ragStats?.sources ?? 0 return [ { @@ -848,8 +875,17 @@ export default function KnowledgeBasePage({ ? 'border-status-critical/25 bg-status-critical/10 text-status-critical' : 'border-status-healthy/25 bg-status-healthy/10 text-status-healthy', }, + { + key: 'ragIndex', + icon: FileSearch, + value: formatCount(ragChunks), + sub: t('decision.card.ragIndexSub', { sources: formatCount(ragSources) }), + tone: ragChunks > 0 + ? 'border-status-healthy/25 bg-status-healthy/10 text-status-healthy' + : 'border-status-critical/25 bg-status-critical/10 text-status-critical', + }, ] as const - }, [formatCount, governanceSummary, t]) + }, [formatCount, governanceSummary, governanceTelemetry.ragStats, t]) const content = (
@@ -1020,7 +1056,7 @@ export default function KnowledgeBasePage({
-
+
{governanceDecisionCards.map(card => { const Icon = card.icon return ( @@ -1095,7 +1131,7 @@ export default function KnowledgeBasePage({ {t('assetLedger.readOnly')}
-
+
{automationAssetRows.map(row => { const Icon = row.icon return (