diff --git a/admin/slices/reins/components/knowledge/SourceStatusBadge.vue b/admin/slices/reins/components/knowledge/SourceStatusBadge.vue index 5cb695ca..dd4560a1 100644 --- a/admin/slices/reins/components/knowledge/SourceStatusBadge.vue +++ b/admin/slices/reins/components/knowledge/SourceStatusBadge.vue @@ -10,6 +10,8 @@ const label = computed(() => { return 'Indexed'; case 'failed': return 'Failed'; + case 'retrying': + return 'Retrying'; case 'pending': return 'Pending'; default: diff --git a/admin/slices/reins/components/knowledge/overview/Provider.vue b/admin/slices/reins/components/knowledge/overview/Provider.vue index ef380dee..a0b16399 100644 --- a/admin/slices/reins/components/knowledge/overview/Provider.vue +++ b/admin/slices/reins/components/knowledge/overview/Provider.vue @@ -15,16 +15,23 @@ const knowledgeId = computed(() => current?.value?.id ?? ''); // reports. const counts = computed(() => { const k = current?.value; - if (!k) return { total: 0, indexed: 0, processing: 0, failed: 0, pending: 0 }; + if (!k) { + return { total: 0, indexed: 0, processing: 0, failed: 0, retrying: 0, pending: 0 }; + } const pending = Math.max( 0, - k.sourceCount - k.indexedCount - k.processingCount - k.failedCount, + k.sourceCount - + k.indexedCount - + k.processingCount - + k.failedCount - + k.retryingCount, ); return { total: k.sourceCount, indexed: k.indexedCount, processing: k.processingCount, failed: k.failedCount, + retrying: k.retryingCount, pending, }; }); @@ -177,6 +184,9 @@ async function save(): Promise { > {{ counts.failed }}

+

+ {{ counts.retrying }} retrying automatically +

{{ counts.pending }} never sent

diff --git a/admin/slices/reins/components/knowledge/sources/Provider.vue b/admin/slices/reins/components/knowledge/sources/Provider.vue index 871ef8f0..9c2dfa2a 100644 --- a/admin/slices/reins/components/knowledge/sources/Provider.vue +++ b/admin/slices/reins/components/knowledge/sources/Provider.vue @@ -9,8 +9,13 @@ import type { SourceIndexStatus, SourceType, } from '#reins/stores/knowledge'; -import { Download, Eye, ScanText, Trash2 } from 'lucide-vue-next'; -import { errorMessageOf, formatBytes, formatDate } from '#reins/domain'; +import { Download, Eye, RefreshCw, ScanText, Trash2 } from 'lucide-vue-next'; +import { + errorMessageOf, + formatBytes, + formatDate, + formatTime, +} from '#reins/domain'; import { Badge } from '#theme/components/ui/badge'; import { Button } from '#theme/components/ui/button'; import { Checkbox } from '#theme/components/ui/checkbox'; @@ -46,8 +51,12 @@ const STATUS_OPTIONS: { value: SourceIndexStatus | 'all'; label: string }[] = [ { value: 'all', label: 'All statuses' }, { value: 'indexed', label: 'Indexed' }, { value: 'pending', label: 'Pending' }, + { value: 'retrying', label: 'Retrying' }, { value: 'failed', label: 'Failed' }, ]; +// One upload plus the API's three automatic retries (MAX_INDEX_RETRIES in +// reins/source/domain/indexFailure.ts); only shown, never enforced here. +const MAX_INDEX_ATTEMPTS = 4; const TYPE_OPTIONS: { value: SourceType | 'all'; label: string }[] = [ { value: 'all', label: 'All types' }, { value: 'file', label: 'File' }, @@ -279,6 +288,15 @@ async function handleReextract(source: ISource) { await load(); } +// A failed row gets another go with a fresh attempt count. When LightRAG +// still holds the document the API schedules it for its reconciler (the row +// reads "Retrying" at once); otherwise it is uploaded again in the background. +async function handleRetry(source: ISource) { + await store.reindexSource(knowledgeId.value, source.id); + await load(); + if (refresh) await refresh(); +} + async function onAdded() { // The new rows land at the end of the list (oldest first), so a user sitting // on a later page or a filter would not see them; go back to a clean view. @@ -439,11 +457,22 @@ async function onAdded() { > {{ s.textError }} + + Attempt {{ s.indexAttempts + 1 }} of {{ MAX_INDEX_ATTEMPTS }}, + next try {{ formatTime(s.indexRetryAt) }} + + {{ s.indexError }} @@ -485,6 +514,16 @@ async function onAdded() { Re-extract text from {{ s.name }} +