AgentEvalTool/frontend/web/src/read/useIntelligentEvalRead.ts

81 lines
2.6 KiB
TypeScript

import { useCallback, useEffect, useLayoutEffect, useReducer, useRef } from 'react'
import {
intelligentEvalReadAdapter,
intelligentEvalReadReducer,
initialIntelligentEvalReadState,
type IntelligentEvalReadAdapter,
type IntelligentEvalReadState,
} from './intelligentEval'
import { usePolling } from '../hooks/usePolling'
const ACTIVE_STATUSES = new Set(['planning', 'pending_approval', 'executing'])
function errorMessage(error: unknown): string {
return error instanceof Error ? error.message : '读取智能评估失败'
}
function isActive(status: string | undefined): boolean {
return status != null && ACTIVE_STATUSES.has(status)
}
export function useIntelligentEvalRead(
selectedId: string | null,
adapter: IntelligentEvalReadAdapter = intelligentEvalReadAdapter,
): IntelligentEvalReadState & { reloadList: () => Promise<void>; reloadDetail: () => Promise<void> } {
const [state, dispatch] = useReducer(intelligentEvalReadReducer, initialIntelligentEvalReadState)
const detailRequestId = useRef(0)
const loadList = useCallback(async (silent = false) => {
dispatch({ type: 'list_requested', silent })
try {
const value = await adapter.list()
dispatch({ type: 'list_succeeded', value })
} catch (error) {
dispatch({ type: 'list_failed', error: errorMessage(error) })
}
}, [adapter])
const loadDetail = useCallback(async (id: string, silent = false) => {
const requestId = ++detailRequestId.current
dispatch({ type: 'detail_requested', id, requestId, silent })
try {
const value = await adapter.get(id)
dispatch({ type: 'detail_succeeded', id, requestId, value })
} catch (error) {
dispatch({ type: 'detail_failed', id, requestId, error: errorMessage(error) })
}
}, [adapter])
useEffect(() => {
void loadList()
}, [loadList])
useLayoutEffect(() => {
if (selectedId == null) {
dispatch({ type: 'detail_cleared', requestId: ++detailRequestId.current })
return
}
void loadDetail(selectedId)
}, [loadDetail, selectedId])
const listActive = state.list.value.some((item) => isActive(item.status))
const detailActive = isActive(state.detail.value?.status)
usePolling(() => { void loadList(true) }, 5000, listActive)
usePolling(
() => {
if (selectedId != null) void loadDetail(selectedId, true)
},
5000,
selectedId != null && detailActive,
)
const reloadList = useCallback(() => loadList(true), [loadList])
const reloadDetail = useCallback(
() => (selectedId == null ? Promise.resolve() : loadDetail(selectedId, true)),
[loadDetail, selectedId],
)
return { ...state, reloadList, reloadDetail }
}