fix: stabilize background operations and large embedding results
This commit is contained in:
@@ -58,9 +58,22 @@ export const useAgentStore = defineStore('agent', () => {
|
||||
tools.value = await agentService.listTools()
|
||||
}
|
||||
|
||||
let listVersion = 0
|
||||
async function loadRuns() {
|
||||
const resp = await agentService.listAgentRuns()
|
||||
runs.value = resp.items
|
||||
const version = ++listVersion
|
||||
const items: AgentRun[] = []
|
||||
let offset = 0
|
||||
do {
|
||||
const resp = await agentService.listAgentRuns({ limit: 100, offset })
|
||||
if (version !== listVersion) return
|
||||
items.push(...resp.items)
|
||||
offset += resp.items.length
|
||||
if (!resp.items.length || offset >= resp.total) break
|
||||
} while (true)
|
||||
const active = runs.value.find(run => run.run_id === activeRunId.value)
|
||||
const merged = new Map(items.map(item => [item.run_id, item]))
|
||||
if (active && !merged.has(active.run_id)) merged.set(active.run_id, active)
|
||||
runs.value = [...merged.values()]
|
||||
}
|
||||
|
||||
async function loadRun(runId: string) {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// @vitest-environment happy-dom
|
||||
import { beforeEach, expect, it, vi } from 'vitest'
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { useTaskStore } from './task'
|
||||
import { useAgentStore } from './agent'
|
||||
const mocks = vi.hoisted(() => ({ tasks: vi.fn(), runs: vi.fn() }))
|
||||
vi.mock('@/services/taskService', () => ({ listTasks: mocks.tasks }))
|
||||
vi.mock('@/services/agentService', () => ({ listAgentRuns: mocks.runs }))
|
||||
beforeEach(() => { setActivePinia(createPinia()); vi.clearAllMocks() })
|
||||
it('loads tasks past the first page before applying global status filters', async () => {
|
||||
const tasks = Array.from({ length: 251 }, (_, i) => ({ task_id: `t${i}`, status: i >= 200 ? 'done' : 'todo' }))
|
||||
mocks.tasks.mockImplementation(async ({ offset, limit }) => ({ items: tasks.slice(offset, offset + limit), total: tasks.length }))
|
||||
const store = useTaskStore()
|
||||
await store.loadTasks()
|
||||
expect(store.tasks).toHaveLength(251)
|
||||
store.setFilterStatus('done')
|
||||
expect(store.filteredTasks).toHaveLength(51)
|
||||
expect(mocks.tasks).toHaveBeenCalledTimes(3)
|
||||
})
|
||||
it('includes older Agent history and leaves failed refresh data intact', async () => {
|
||||
const runs = Array.from({ length: 201 }, (_, i) => ({ run_id: `r${i}`, status: 'completed' }))
|
||||
mocks.runs.mockImplementation(async ({ offset, limit }) => ({ items: runs.slice(offset, offset + limit), total: runs.length }))
|
||||
const store = useAgentStore()
|
||||
await store.loadRuns()
|
||||
expect(store.runs).toHaveLength(201)
|
||||
mocks.runs.mockRejectedValue(new Error('offline'))
|
||||
await expect(store.loadRuns()).rejects.toThrow('offline')
|
||||
expect(store.runs).toHaveLength(201)
|
||||
})
|
||||
@@ -1,5 +1,5 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, watch } from 'vue'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import type { AiCoreStatus, IndexStatus } from '@/contracts'
|
||||
import { resolveApiUrl } from '@/services/apiClient'
|
||||
import packageInfo from '../../package.json'
|
||||
@@ -31,6 +31,15 @@ export const useSettingsStore = defineStore('settings', () => {
|
||||
// Index
|
||||
const emptyIndex = (): IndexStatus => ({ status: 'unknown', pending_jobs: 0, total_notes: null, total_blocks: null })
|
||||
const indexStatus = ref<IndexStatus>(emptyIndex())
|
||||
const indexStatusLabel = computed(() => {
|
||||
const value = indexStatus.value
|
||||
if (value.status === 'unknown') return t('索引状态未获取', 'Index status unavailable')
|
||||
if (value.status === 'indexing') return t('后台计算索引', 'Indexing in background')
|
||||
if (value.status === 'error') return t('索引错误', 'Index error')
|
||||
if (value.vector_refresh_required) return t('全文可用 · 向量待重建', 'Full text ready · vectors need rebuilding')
|
||||
if (value.active_searches) return t('向量检索中', 'Vector search running')
|
||||
return t('索引就绪', 'Index ready')
|
||||
})
|
||||
|
||||
// Permissions
|
||||
const permissionPolicy = ref<Record<string, 'allow' | 'confirm' | 'deny'>>({})
|
||||
@@ -85,6 +94,7 @@ export const useSettingsStore = defineStore('settings', () => {
|
||||
aiCoreStatus,
|
||||
aiCoreAddress,
|
||||
indexStatus,
|
||||
indexStatusLabel,
|
||||
permissionPolicy,
|
||||
diagnosticsError,
|
||||
loadDiagnostics,
|
||||
|
||||
@@ -25,16 +25,27 @@ export const useTaskStore = defineStore('task', () => {
|
||||
const inProgressTasks = computed(() => tasks.value.filter((t) => t.status === 'in_progress'))
|
||||
const doneTasks = computed(() => tasks.value.filter((t) => t.status === 'done'))
|
||||
|
||||
let loadVersion = 0
|
||||
async function loadTasks() {
|
||||
const version = ++loadVersion
|
||||
isLoading.value = true
|
||||
try {
|
||||
const resp = await listTasks()
|
||||
tasks.value = resp.items
|
||||
const items: TaskItem[] = []
|
||||
let offset = 0
|
||||
do {
|
||||
const resp = await listTasks({ limit: 100, offset })
|
||||
if (version !== loadVersion) return
|
||||
items.push(...resp.items)
|
||||
offset += resp.items.length
|
||||
if (!resp.items.length || offset >= resp.total) break
|
||||
} while (true)
|
||||
tasks.value = [...new Map(items.map(item => [item.task_id, item])).values()]
|
||||
error.value = null
|
||||
} catch (reason) {
|
||||
if (version !== loadVersion) return
|
||||
error.value = reason instanceof Error ? reason.message : t('任务加载失败', 'Failed to load tasks')
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
if (version === loadVersion) isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user