@ash-ai/dashboard 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/agents/detail/page.tsx +182 -0
- package/app/agents/eval-compare/page.tsx +445 -0
- package/app/agents/eval-run/page.tsx +331 -0
- package/app/agents/eval-runs/page.tsx +376 -0
- package/app/agents/evals/page.tsx +448 -0
- package/app/agents/knowledge/page.tsx +202 -0
- package/app/agents/page.tsx +5 -3
- package/app/agents/versions/page.tsx +280 -0
- package/lib/hooks.ts +120 -0
- package/out/404/index.html +1 -1
- package/out/404.html +1 -1
- package/out/_next/static/chunks/839-186b95b4d095e127.js +1 -0
- package/out/_next/static/chunks/90-8e47c31ab931867f.js +1 -0
- package/out/_next/static/chunks/{929-6faf1adeb65ee383.js → 929-b631fe082fe4e852.js} +1 -1
- package/out/_next/static/chunks/app/agents/detail/page-7427483b9c74ad63.js +1 -0
- package/out/_next/static/chunks/app/agents/eval-compare/page-bc4e8051ba07e56f.js +1 -0
- package/out/_next/static/chunks/app/agents/eval-run/page-a38dac74d1b3787d.js +1 -0
- package/out/_next/static/chunks/app/agents/eval-runs/page-af2fb33c0fce7934.js +1 -0
- package/out/_next/static/chunks/app/agents/evals/page-6bdc4b839a7a8eda.js +1 -0
- package/out/_next/static/chunks/app/agents/knowledge/page-0e02b14bfa2a6d04.js +1 -0
- package/out/_next/static/chunks/app/agents/page-99f179eb7c41ebd4.js +1 -0
- package/out/_next/static/chunks/app/agents/versions/page-c482d9bad8f35df6.js +1 -0
- package/out/_next/static/chunks/app/analytics/page-ca5d8c60e62118ed.js +1 -0
- package/out/_next/static/chunks/app/layout-b06d1caafc026d0c.js +1 -0
- package/out/_next/static/chunks/app/logs/page-1a7df17a605f36d3.js +1 -0
- package/out/_next/static/chunks/app/page-9e02cb0e8897ab5d.js +1 -0
- package/out/_next/static/chunks/app/playground/{page-10d3461f118bfb21.js → page-cb17c2ffaeb31b4e.js} +1 -1
- package/out/_next/static/chunks/app/queue/page-6013b93817822c75.js +1 -0
- package/out/_next/static/chunks/app/sessions/page-add67d96ab66b690.js +1 -0
- package/out/_next/static/chunks/app/settings/credentials/page-ffe97ffb2f60229d.js +1 -0
- package/out/_next/static/css/ab505eeeff3f7df5.css +1 -0
- package/out/_next/static/sXYgh3eUKXRKt1T_1T3tk/_buildManifest.js +1 -0
- package/out/agents/detail/index.html +1 -0
- package/out/agents/detail/index.txt +22 -0
- package/out/agents/eval-compare/index.html +1 -0
- package/out/agents/eval-compare/index.txt +22 -0
- package/out/agents/eval-run/index.html +1 -0
- package/out/agents/eval-run/index.txt +22 -0
- package/out/agents/eval-runs/index.html +1 -0
- package/out/agents/eval-runs/index.txt +22 -0
- package/out/agents/evals/index.html +1 -0
- package/out/agents/evals/index.txt +22 -0
- package/out/agents/index.html +1 -1
- package/out/agents/index.txt +6 -6
- package/out/agents/knowledge/index.html +1 -0
- package/out/agents/knowledge/index.txt +22 -0
- package/out/agents/versions/index.html +1 -0
- package/out/agents/versions/index.txt +22 -0
- package/out/analytics/index.html +1 -1
- package/out/analytics/index.txt +6 -6
- package/out/index.html +1 -1
- package/out/index.txt +6 -6
- package/out/logs/index.html +1 -1
- package/out/logs/index.txt +6 -6
- package/out/playground/index.html +1 -1
- package/out/playground/index.txt +6 -6
- package/out/queue/index.html +1 -1
- package/out/queue/index.txt +6 -6
- package/out/sessions/index.html +1 -1
- package/out/sessions/index.txt +6 -6
- package/out/settings/api-keys/index.html +1 -1
- package/out/settings/api-keys/index.txt +6 -6
- package/out/settings/credentials/index.html +1 -1
- package/out/settings/credentials/index.txt +6 -6
- package/package.json +4 -4
- package/out/_next/static/_fEfzU87y-4u457akpPDC/_buildManifest.js +0 -1
- package/out/_next/static/chunks/322-bab4df5c5188e993.js +0 -1
- package/out/_next/static/chunks/432-11ec8af7ccfbd019.js +0 -1
- package/out/_next/static/chunks/app/agents/page-5f872b5fa12d7854.js +0 -1
- package/out/_next/static/chunks/app/analytics/page-bb296f848e25a94f.js +0 -1
- package/out/_next/static/chunks/app/layout-f5d1d76b525135c7.js +0 -1
- package/out/_next/static/chunks/app/logs/page-5165b556d13654ae.js +0 -1
- package/out/_next/static/chunks/app/page-d1e6d7bff1216f08.js +0 -1
- package/out/_next/static/chunks/app/queue/page-50142f2cfb3664e7.js +0 -1
- package/out/_next/static/chunks/app/sessions/page-7f55a0a4ba0be458.js +0 -1
- package/out/_next/static/chunks/app/settings/credentials/page-deb5556bfe57b8b9.js +0 -1
- package/out/_next/static/css/15bfa5d891bcf58c.css +0 -1
- /package/out/_next/static/{_fEfzU87y-4u457akpPDC → sXYgh3eUKXRKt1T_1T3tk}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { Suspense, useState, useEffect } from 'react'
|
|
4
|
+
import { useSearchParams } from 'next/navigation'
|
|
5
|
+
import Link from 'next/link'
|
|
6
|
+
import { useEvalRuns, useAgentVersions } from '@/lib/hooks'
|
|
7
|
+
import { getClient } from '@/lib/client'
|
|
8
|
+
import { Card, CardContent } from '@/components/ui/card'
|
|
9
|
+
import { Button } from '@/components/ui/button'
|
|
10
|
+
import { Select } from '@/components/ui/select'
|
|
11
|
+
import { Badge } from '@/components/ui/badge'
|
|
12
|
+
import { EmptyState } from '@/components/ui/empty-state'
|
|
13
|
+
import { ShimmerBlock } from '@/components/ui/shimmer'
|
|
14
|
+
import { formatRelativeTime, truncateId } from '@/lib/utils'
|
|
15
|
+
import {
|
|
16
|
+
ArrowLeft,
|
|
17
|
+
Play,
|
|
18
|
+
BarChart3,
|
|
19
|
+
Loader2,
|
|
20
|
+
GitCompare,
|
|
21
|
+
CheckCircle2,
|
|
22
|
+
XCircle,
|
|
23
|
+
Clock,
|
|
24
|
+
AlertTriangle,
|
|
25
|
+
X,
|
|
26
|
+
} from 'lucide-react'
|
|
27
|
+
|
|
28
|
+
function statusIcon(status: string) {
|
|
29
|
+
switch (status) {
|
|
30
|
+
case 'completed':
|
|
31
|
+
return <CheckCircle2 className="h-4 w-4 text-green-400" />
|
|
32
|
+
case 'running':
|
|
33
|
+
return <Loader2 className="h-4 w-4 text-blue-400 animate-spin" />
|
|
34
|
+
case 'failed':
|
|
35
|
+
return <XCircle className="h-4 w-4 text-red-400" />
|
|
36
|
+
case 'pending':
|
|
37
|
+
return <Clock className="h-4 w-4 text-yellow-400" />
|
|
38
|
+
default:
|
|
39
|
+
return <AlertTriangle className="h-4 w-4 text-white/40" />
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function statusVariant(status: string): 'success' | 'info' | 'error' | 'warning' | 'default' {
|
|
44
|
+
switch (status) {
|
|
45
|
+
case 'completed': return 'success'
|
|
46
|
+
case 'running': return 'info'
|
|
47
|
+
case 'failed': return 'error'
|
|
48
|
+
case 'pending': return 'warning'
|
|
49
|
+
default: return 'default'
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function EvalRunsContent() {
|
|
54
|
+
const searchParams = useSearchParams()
|
|
55
|
+
const name = searchParams.get('name')
|
|
56
|
+
const { runs, loading, refresh } = useEvalRuns(name)
|
|
57
|
+
const { versions } = useAgentVersions(name)
|
|
58
|
+
const [showRunModal, setShowRunModal] = useState(false)
|
|
59
|
+
const [compareMode, setCompareMode] = useState(false)
|
|
60
|
+
const [selectedRuns, setSelectedRuns] = useState<string[]>([])
|
|
61
|
+
const [error, setError] = useState<string | null>(null)
|
|
62
|
+
|
|
63
|
+
// Auto-refresh when there are running runs
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
const hasRunning = runs.some((r: any) => r.status === 'running' || r.status === 'pending')
|
|
66
|
+
if (!hasRunning) return
|
|
67
|
+
const interval = setInterval(() => refresh(), 5000)
|
|
68
|
+
return () => clearInterval(interval)
|
|
69
|
+
}, [runs, refresh])
|
|
70
|
+
|
|
71
|
+
function toggleRunSelection(runId: string) {
|
|
72
|
+
setSelectedRuns((prev) => {
|
|
73
|
+
if (prev.includes(runId)) return prev.filter((id) => id !== runId)
|
|
74
|
+
if (prev.length >= 2) return [prev[1], runId]
|
|
75
|
+
return [...prev, runId]
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!name) {
|
|
80
|
+
return (
|
|
81
|
+
<div className="text-center py-16">
|
|
82
|
+
<p className="text-white/50">No agent name specified.</p>
|
|
83
|
+
<Link href="/agents" className="text-indigo-400 hover:text-indigo-300 text-sm mt-2 inline-block">
|
|
84
|
+
Back to agents
|
|
85
|
+
</Link>
|
|
86
|
+
</div>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<div className="space-y-6">
|
|
92
|
+
{/* Back link */}
|
|
93
|
+
<Link
|
|
94
|
+
href={`/agents/evals?name=${encodeURIComponent(name)}`}
|
|
95
|
+
className="inline-flex items-center gap-1.5 text-sm text-white/50 hover:text-white transition-colors"
|
|
96
|
+
>
|
|
97
|
+
<ArrowLeft className="h-4 w-4" />
|
|
98
|
+
Back to eval cases
|
|
99
|
+
</Link>
|
|
100
|
+
|
|
101
|
+
<div className="flex items-center justify-between">
|
|
102
|
+
<div>
|
|
103
|
+
<h1 className="text-2xl font-bold text-white">Eval Runs</h1>
|
|
104
|
+
<p className="mt-1 text-sm text-white/50">
|
|
105
|
+
Run history for <span className="text-white/70">{name}</span>
|
|
106
|
+
</p>
|
|
107
|
+
</div>
|
|
108
|
+
<div className="flex items-center gap-2">
|
|
109
|
+
{runs.length >= 2 && (
|
|
110
|
+
<Button
|
|
111
|
+
variant={compareMode ? 'primary' : 'secondary'}
|
|
112
|
+
onClick={() => {
|
|
113
|
+
setCompareMode(!compareMode)
|
|
114
|
+
setSelectedRuns([])
|
|
115
|
+
}}
|
|
116
|
+
>
|
|
117
|
+
<GitCompare className="h-4 w-4 mr-2" />
|
|
118
|
+
{compareMode ? 'Cancel Compare' : 'Compare'}
|
|
119
|
+
</Button>
|
|
120
|
+
)}
|
|
121
|
+
{compareMode && selectedRuns.length === 2 && (
|
|
122
|
+
<Link
|
|
123
|
+
href={`/agents/eval-compare?name=${encodeURIComponent(name)}&runA=${selectedRuns[0]}&runB=${selectedRuns[1]}`}
|
|
124
|
+
>
|
|
125
|
+
<Button>
|
|
126
|
+
<BarChart3 className="h-4 w-4 mr-2" />
|
|
127
|
+
Compare Selected
|
|
128
|
+
</Button>
|
|
129
|
+
</Link>
|
|
130
|
+
)}
|
|
131
|
+
{!compareMode && (
|
|
132
|
+
<Button onClick={() => setShowRunModal(true)}>
|
|
133
|
+
<Play className="h-4 w-4 mr-2" />
|
|
134
|
+
Run Evals
|
|
135
|
+
</Button>
|
|
136
|
+
)}
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
{error && (
|
|
141
|
+
<div className="text-sm text-red-400 bg-red-500/10 border border-red-500/20 rounded-lg px-4 py-2">
|
|
142
|
+
{error}
|
|
143
|
+
</div>
|
|
144
|
+
)}
|
|
145
|
+
|
|
146
|
+
{compareMode && (
|
|
147
|
+
<div className="text-sm text-white/50 bg-indigo-500/5 border border-indigo-500/20 rounded-lg px-4 py-2">
|
|
148
|
+
Select 2 runs to compare. Selected: {selectedRuns.length}/2
|
|
149
|
+
</div>
|
|
150
|
+
)}
|
|
151
|
+
|
|
152
|
+
{loading ? (
|
|
153
|
+
<div className="space-y-3">
|
|
154
|
+
{[1, 2, 3].map((i) => (
|
|
155
|
+
<ShimmerBlock key={i} height={80} />
|
|
156
|
+
))}
|
|
157
|
+
</div>
|
|
158
|
+
) : runs.length === 0 ? (
|
|
159
|
+
<EmptyState
|
|
160
|
+
icon={<BarChart3 className="h-12 w-12" />}
|
|
161
|
+
title="No eval runs yet"
|
|
162
|
+
description="Start an eval run to test your agent against the defined eval cases."
|
|
163
|
+
action={
|
|
164
|
+
<Button onClick={() => setShowRunModal(true)}>
|
|
165
|
+
<Play className="h-4 w-4 mr-2" />
|
|
166
|
+
Run Evals
|
|
167
|
+
</Button>
|
|
168
|
+
}
|
|
169
|
+
/>
|
|
170
|
+
) : (
|
|
171
|
+
<div className="space-y-3">
|
|
172
|
+
{runs.map((run: any) => {
|
|
173
|
+
const isSelected = selectedRuns.includes(run.id)
|
|
174
|
+
return (
|
|
175
|
+
<Card
|
|
176
|
+
key={run.id}
|
|
177
|
+
className={compareMode && isSelected ? 'border-indigo-500/50 bg-indigo-500/5' : ''}
|
|
178
|
+
>
|
|
179
|
+
<CardContent>
|
|
180
|
+
<div className="flex items-center justify-between">
|
|
181
|
+
<div className="flex items-center gap-3 min-w-0 flex-1">
|
|
182
|
+
{compareMode && (
|
|
183
|
+
<button
|
|
184
|
+
onClick={() => toggleRunSelection(run.id)}
|
|
185
|
+
className={`flex-shrink-0 h-5 w-5 rounded border-2 transition-colors ${
|
|
186
|
+
isSelected
|
|
187
|
+
? 'bg-indigo-500 border-indigo-500'
|
|
188
|
+
: 'border-white/20 hover:border-white/40'
|
|
189
|
+
}`}
|
|
190
|
+
>
|
|
191
|
+
{isSelected && <CheckCircle2 className="h-4 w-4 text-white" />}
|
|
192
|
+
</button>
|
|
193
|
+
)}
|
|
194
|
+
{statusIcon(run.status)}
|
|
195
|
+
<div className="min-w-0">
|
|
196
|
+
<div className="flex items-center gap-2">
|
|
197
|
+
{!compareMode ? (
|
|
198
|
+
<Link
|
|
199
|
+
href={`/agents/eval-run?name=${encodeURIComponent(name)}&runId=${run.id}`}
|
|
200
|
+
className="text-sm font-semibold text-white hover:text-indigo-400 transition-colors"
|
|
201
|
+
>
|
|
202
|
+
Run {truncateId(run.id)}
|
|
203
|
+
</Link>
|
|
204
|
+
) : (
|
|
205
|
+
<span className="text-sm font-semibold text-white">
|
|
206
|
+
Run {truncateId(run.id)}
|
|
207
|
+
</span>
|
|
208
|
+
)}
|
|
209
|
+
<Badge variant={statusVariant(run.status)}>{run.status}</Badge>
|
|
210
|
+
{run.versionNumber !== null && run.versionNumber !== undefined && (
|
|
211
|
+
<Badge variant="default">v{run.versionNumber}</Badge>
|
|
212
|
+
)}
|
|
213
|
+
</div>
|
|
214
|
+
<div className="flex items-center gap-3 mt-1">
|
|
215
|
+
<span className="text-xs text-white/30">
|
|
216
|
+
{formatRelativeTime(run.createdAt)}
|
|
217
|
+
</span>
|
|
218
|
+
<span className="text-xs text-white/30">
|
|
219
|
+
{run.completedCases}/{run.totalCases} cases
|
|
220
|
+
</span>
|
|
221
|
+
</div>
|
|
222
|
+
</div>
|
|
223
|
+
</div>
|
|
224
|
+
{run.summary && (
|
|
225
|
+
<div className="flex items-center gap-4 flex-shrink-0">
|
|
226
|
+
<div className="text-right">
|
|
227
|
+
<div className="text-xs text-white/40">Pass Rate</div>
|
|
228
|
+
<div className={`text-sm font-semibold ${
|
|
229
|
+
run.summary.passRate >= 0.8
|
|
230
|
+
? 'text-green-400'
|
|
231
|
+
: run.summary.passRate >= 0.5
|
|
232
|
+
? 'text-yellow-400'
|
|
233
|
+
: 'text-red-400'
|
|
234
|
+
}`}>
|
|
235
|
+
{(run.summary.passRate * 100).toFixed(0)}%
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
<div className="text-right">
|
|
239
|
+
<div className="text-xs text-white/40">Topic</div>
|
|
240
|
+
<div className="text-sm font-semibold text-white">
|
|
241
|
+
{run.summary.avgTopicScore.toFixed(2)}
|
|
242
|
+
</div>
|
|
243
|
+
</div>
|
|
244
|
+
<div className="text-right">
|
|
245
|
+
<div className="text-xs text-white/40">Safety</div>
|
|
246
|
+
<div className="text-sm font-semibold text-white">
|
|
247
|
+
{run.summary.avgSafetyScore.toFixed(2)}
|
|
248
|
+
</div>
|
|
249
|
+
</div>
|
|
250
|
+
<div className="text-right">
|
|
251
|
+
<div className="text-xs text-white/40">Latency</div>
|
|
252
|
+
<div className="text-sm font-semibold text-white">
|
|
253
|
+
{run.summary.avgLatencyMs.toFixed(0)}ms
|
|
254
|
+
</div>
|
|
255
|
+
</div>
|
|
256
|
+
</div>
|
|
257
|
+
)}
|
|
258
|
+
</div>
|
|
259
|
+
</CardContent>
|
|
260
|
+
</Card>
|
|
261
|
+
)
|
|
262
|
+
})}
|
|
263
|
+
</div>
|
|
264
|
+
)}
|
|
265
|
+
|
|
266
|
+
{/* Run Evals Modal */}
|
|
267
|
+
{showRunModal && (
|
|
268
|
+
<RunEvalsModal
|
|
269
|
+
agentName={name}
|
|
270
|
+
versions={versions}
|
|
271
|
+
onClose={() => setShowRunModal(false)}
|
|
272
|
+
onStarted={() => {
|
|
273
|
+
setShowRunModal(false)
|
|
274
|
+
refresh()
|
|
275
|
+
}}
|
|
276
|
+
/>
|
|
277
|
+
)}
|
|
278
|
+
</div>
|
|
279
|
+
)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// ─── Run Evals Modal ───
|
|
283
|
+
|
|
284
|
+
function RunEvalsModal({
|
|
285
|
+
agentName,
|
|
286
|
+
versions,
|
|
287
|
+
onClose,
|
|
288
|
+
onStarted,
|
|
289
|
+
}: {
|
|
290
|
+
agentName: string
|
|
291
|
+
versions: any[]
|
|
292
|
+
onClose: () => void
|
|
293
|
+
onStarted: () => void
|
|
294
|
+
}) {
|
|
295
|
+
const [versionNumber, setVersionNumber] = useState<string>('')
|
|
296
|
+
const [starting, setStarting] = useState(false)
|
|
297
|
+
const [error, setError] = useState<string | null>(null)
|
|
298
|
+
|
|
299
|
+
async function handleStart() {
|
|
300
|
+
setStarting(true)
|
|
301
|
+
setError(null)
|
|
302
|
+
try {
|
|
303
|
+
await getClient().startEvalRun(agentName, {
|
|
304
|
+
versionNumber: versionNumber ? Number(versionNumber) : undefined,
|
|
305
|
+
})
|
|
306
|
+
onStarted()
|
|
307
|
+
} catch (e) {
|
|
308
|
+
setError(e instanceof Error ? e.message : 'Failed to start eval run')
|
|
309
|
+
} finally {
|
|
310
|
+
setStarting(false)
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const versionOptions = versions.map((v: any) => ({
|
|
315
|
+
value: String(v.versionNumber),
|
|
316
|
+
label: `v${v.versionNumber}${v.name ? ` - ${v.name}` : ''}${v.isActive ? ' (active)' : ''}`,
|
|
317
|
+
}))
|
|
318
|
+
|
|
319
|
+
return (
|
|
320
|
+
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm">
|
|
321
|
+
<Card className="w-full max-w-md">
|
|
322
|
+
<CardContent>
|
|
323
|
+
<div className="flex items-center justify-between mb-6">
|
|
324
|
+
<h2 className="text-lg font-semibold text-white">Run Evals</h2>
|
|
325
|
+
<button onClick={onClose} className="text-white/40 hover:text-white">
|
|
326
|
+
<X className="h-5 w-5" />
|
|
327
|
+
</button>
|
|
328
|
+
</div>
|
|
329
|
+
|
|
330
|
+
<div className="space-y-4">
|
|
331
|
+
<Select
|
|
332
|
+
label="Version (optional)"
|
|
333
|
+
placeholder="Use active version"
|
|
334
|
+
options={versionOptions}
|
|
335
|
+
value={versionNumber}
|
|
336
|
+
onChange={(e) => setVersionNumber(e.target.value)}
|
|
337
|
+
/>
|
|
338
|
+
|
|
339
|
+
<p className="text-xs text-white/40">
|
|
340
|
+
This will run all active eval cases against the selected version of the agent.
|
|
341
|
+
</p>
|
|
342
|
+
|
|
343
|
+
{error && <p className="text-sm text-red-400">{error}</p>}
|
|
344
|
+
|
|
345
|
+
<div className="flex justify-end gap-3 pt-2">
|
|
346
|
+
<Button variant="ghost" onClick={onClose}>
|
|
347
|
+
Cancel
|
|
348
|
+
</Button>
|
|
349
|
+
<Button onClick={handleStart} disabled={starting}>
|
|
350
|
+
{starting ? (
|
|
351
|
+
<>
|
|
352
|
+
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
|
|
353
|
+
Starting...
|
|
354
|
+
</>
|
|
355
|
+
) : (
|
|
356
|
+
<>
|
|
357
|
+
<Play className="h-4 w-4 mr-2" />
|
|
358
|
+
Start Run
|
|
359
|
+
</>
|
|
360
|
+
)}
|
|
361
|
+
</Button>
|
|
362
|
+
</div>
|
|
363
|
+
</div>
|
|
364
|
+
</CardContent>
|
|
365
|
+
</Card>
|
|
366
|
+
</div>
|
|
367
|
+
)
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export default function EvalRunsPage() {
|
|
371
|
+
return (
|
|
372
|
+
<Suspense fallback={<ShimmerBlock height={200} />}>
|
|
373
|
+
<EvalRunsContent />
|
|
374
|
+
</Suspense>
|
|
375
|
+
)
|
|
376
|
+
}
|