Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
1. App.tsx: add restoreSession() call on startup to prevent redirect to login page after refresh (isRestoring guard + BootstrapScreen) 2. CloneManager: call syncAgents() after loadClones() to restore currentAgent and conversation history on app load 3. zclaw-memory: add get_or_create_session() so frontend session UUID is persisted directly — kernel no longer creates mismatched IDs 4. openai.rs: assistant message content must be non-empty for Kimi/Qwen APIs — replace empty content with meaningful placeholders Also includes admin-v2 ModelServices unified page (merge providers + models + API keys into expandable row layout)
147 lines
4.0 KiB
TypeScript
147 lines
4.0 KiB
TypeScript
// ============================================================
|
|
// 中转任务
|
|
// ============================================================
|
|
|
|
import { useState } from 'react'
|
|
import { useQuery } from '@tanstack/react-query'
|
|
import { Tag, Select } from 'antd'
|
|
import type { ProColumns } from '@ant-design/pro-components'
|
|
import { ProTable } from '@ant-design/pro-components'
|
|
import { relayService } from '@/services/relay'
|
|
import { PageHeader } from '@/components/PageHeader'
|
|
import { ErrorState } from '@/components/ErrorState'
|
|
import type { RelayTask } from '@/types'
|
|
|
|
const statusLabels: Record<string, string> = {
|
|
queued: '排队中',
|
|
running: '运行中',
|
|
completed: '已完成',
|
|
failed: '失败',
|
|
cancelled: '已取消',
|
|
}
|
|
|
|
const statusColors: Record<string, string> = {
|
|
queued: 'default',
|
|
running: 'processing',
|
|
completed: 'green',
|
|
failed: 'red',
|
|
cancelled: 'default',
|
|
}
|
|
|
|
export default function Relay() {
|
|
const [statusFilter, setStatusFilter] = useState<string | undefined>(undefined)
|
|
const [page, setPage] = useState(1)
|
|
|
|
const {
|
|
data,
|
|
isLoading,
|
|
error,
|
|
refetch,
|
|
} = useQuery({
|
|
queryKey: ['relay-tasks', page, statusFilter],
|
|
queryFn: ({ signal }) => relayService.list({ page, page_size: 20, status: statusFilter }, signal),
|
|
})
|
|
|
|
if (error) {
|
|
return (
|
|
<>
|
|
<PageHeader title="中转任务" description="查看和管理 AI 模型中转请求" />
|
|
<ErrorState message={(error as Error).message} onRetry={() => refetch()} />
|
|
</>
|
|
)
|
|
}
|
|
|
|
const columns: ProColumns<RelayTask>[] = [
|
|
{
|
|
title: 'ID',
|
|
dataIndex: 'id',
|
|
width: 120,
|
|
render: (_, r) => (
|
|
<code className="text-xs px-1.5 py-0.5 rounded bg-neutral-100 dark:bg-neutral-800">
|
|
{r.id.substring(0, 8)}...
|
|
</code>
|
|
),
|
|
},
|
|
{
|
|
title: '状态',
|
|
dataIndex: 'status',
|
|
width: 100,
|
|
render: (_, r) => (
|
|
<Tag color={statusColors[r.status] || 'default'}>
|
|
{statusLabels[r.status] || r.status}
|
|
</Tag>
|
|
),
|
|
},
|
|
{ title: '模型', dataIndex: 'model_id', width: 160 },
|
|
{ title: '优先级', dataIndex: 'priority', width: 70 },
|
|
{ title: '尝试次数', dataIndex: 'attempt_count', width: 80 },
|
|
{
|
|
title: 'Token (入/出)',
|
|
width: 140,
|
|
render: (_, r) => (
|
|
<span className="text-sm">
|
|
{r.input_tokens.toLocaleString()} / {r.output_tokens.toLocaleString()}
|
|
</span>
|
|
),
|
|
},
|
|
{ title: '错误信息', dataIndex: 'error_message', width: 200, ellipsis: true },
|
|
{
|
|
title: '排队时间',
|
|
dataIndex: 'queued_at',
|
|
width: 180,
|
|
render: (_, r) => new Date(r.queued_at).toLocaleString('zh-CN'),
|
|
},
|
|
{
|
|
title: '完成时间',
|
|
dataIndex: 'completed_at',
|
|
width: 180,
|
|
render: (_, r) => (r.completed_at ? new Date(r.completed_at).toLocaleString('zh-CN') : '-'),
|
|
},
|
|
]
|
|
|
|
return (
|
|
<div>
|
|
<PageHeader
|
|
title="中转任务"
|
|
description="查看和管理 AI 模型中转请求"
|
|
actions={
|
|
<Select
|
|
value={statusFilter}
|
|
onChange={(v) => {
|
|
setStatusFilter(v === 'all' ? undefined : v)
|
|
setPage(1)
|
|
}}
|
|
placeholder="状态筛选"
|
|
className="w-36"
|
|
allowClear
|
|
options={[
|
|
{ value: 'all', label: '全部' },
|
|
{ value: 'queued', label: '排队中' },
|
|
{ value: 'running', label: '运行中' },
|
|
{ value: 'completed', label: '已完成' },
|
|
{ value: 'failed', label: '失败' },
|
|
{ value: 'cancelled', label: '已取消' },
|
|
]}
|
|
/>
|
|
}
|
|
/>
|
|
|
|
<ProTable<RelayTask>
|
|
columns={columns}
|
|
dataSource={data?.items ?? []}
|
|
loading={isLoading}
|
|
rowKey="id"
|
|
search={false}
|
|
toolBarRender={false}
|
|
pagination={{
|
|
total: data?.total ?? 0,
|
|
pageSize: 20,
|
|
current: page,
|
|
onChange: setPage,
|
|
showSizeChanger: false,
|
|
}}
|
|
/>
|
|
</div>
|
|
)
|
|
}
|