mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-19 16:02:14 +00:00
7a7d246a6e
* feat: add global ai eval mode * fix: improve global eval validation feedback
147 lines
3.9 KiB
TypeScript
147 lines
3.9 KiB
TypeScript
export type FrontendBenchmarkProgressSurface = 'flow' | 'app' | 'script' | 'global'
|
|
|
|
export type FrontendBenchmarkProgressEvent =
|
|
| {
|
|
type: 'run-start'
|
|
surface: FrontendBenchmarkProgressSurface
|
|
totalCases: number
|
|
runs: number
|
|
concurrency: number
|
|
}
|
|
| {
|
|
type: 'attempt-start'
|
|
surface: FrontendBenchmarkProgressSurface
|
|
caseId: string
|
|
caseNumber: number
|
|
totalCases: number
|
|
attempt: number
|
|
runs: number
|
|
}
|
|
| {
|
|
type: 'attempt-finish'
|
|
surface: FrontendBenchmarkProgressSurface
|
|
caseId: string
|
|
caseNumber: number
|
|
totalCases: number
|
|
attempt: number
|
|
runs: number
|
|
passed: boolean
|
|
durationMs: number
|
|
judgeScore: number | null
|
|
error: string | null
|
|
}
|
|
| {
|
|
type: 'assistant-message-start'
|
|
surface: FrontendBenchmarkProgressSurface
|
|
caseId: string
|
|
caseNumber: number
|
|
totalCases: number
|
|
attempt: number
|
|
runs: number
|
|
}
|
|
| {
|
|
type: 'assistant-chunk'
|
|
surface: FrontendBenchmarkProgressSurface
|
|
caseId: string
|
|
caseNumber: number
|
|
totalCases: number
|
|
attempt: number
|
|
runs: number
|
|
chunk: string
|
|
}
|
|
| {
|
|
type: 'assistant-message-end'
|
|
surface: FrontendBenchmarkProgressSurface
|
|
caseId: string
|
|
caseNumber: number
|
|
totalCases: number
|
|
attempt: number
|
|
runs: number
|
|
}
|
|
| {
|
|
type: 'tool-call'
|
|
surface: FrontendBenchmarkProgressSurface
|
|
caseId: string
|
|
caseNumber: number
|
|
totalCases: number
|
|
attempt: number
|
|
runs: number
|
|
toolName: string
|
|
argumentsText: string
|
|
}
|
|
|
|
export const FRONTEND_BENCHMARK_PROGRESS_PREFIX = 'WMILL_FRONTEND_AI_EVAL_PROGRESS '
|
|
|
|
export function emitFrontendBenchmarkProgress(event: FrontendBenchmarkProgressEvent): void {
|
|
process.stderr.write(
|
|
`${FRONTEND_BENCHMARK_PROGRESS_PREFIX}${JSON.stringify(event)}\n`
|
|
)
|
|
}
|
|
|
|
export function parseFrontendBenchmarkProgressLine(
|
|
line: string
|
|
): FrontendBenchmarkProgressEvent | null {
|
|
if (!line.startsWith(FRONTEND_BENCHMARK_PROGRESS_PREFIX)) {
|
|
return null
|
|
}
|
|
|
|
try {
|
|
const parsed = JSON.parse(
|
|
line.slice(FRONTEND_BENCHMARK_PROGRESS_PREFIX.length)
|
|
) as FrontendBenchmarkProgressEvent
|
|
return parsed?.type ? parsed : null
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
export function formatFrontendBenchmarkProgressEvent(
|
|
event: FrontendBenchmarkProgressEvent
|
|
): string {
|
|
switch (event.type) {
|
|
case 'run-start':
|
|
return `Running ${event.surface}: ${event.totalCases} cases x ${event.runs} run${event.runs === 1 ? '' : 's'}, concurrency ${event.concurrency}`
|
|
case 'attempt-start':
|
|
return `${formatCasePrefix(event.caseNumber, event.totalCases)} ${event.caseId} attempt ${event.attempt}/${event.runs}...`
|
|
case 'attempt-finish': {
|
|
const parts = [
|
|
`${formatCasePrefix(event.caseNumber, event.totalCases)} ${event.caseId} attempt ${event.attempt}/${event.runs} ${event.passed ? 'pass' : 'fail'}`,
|
|
formatDuration(event.durationMs)
|
|
]
|
|
if (event.judgeScore !== null) {
|
|
parts.push(`judge ${formatNumber(event.judgeScore)}`)
|
|
}
|
|
if (event.error) {
|
|
parts.push(truncateSingleLine(event.error, 120))
|
|
}
|
|
return parts.join(' | ')
|
|
}
|
|
case 'assistant-message-start':
|
|
case 'assistant-chunk':
|
|
case 'assistant-message-end':
|
|
return ''
|
|
case 'tool-call':
|
|
return `${formatCasePrefix(event.caseNumber, event.totalCases)} ${event.caseId} attempt ${event.attempt}/${event.runs} tool ${event.toolName} ${truncateSingleLine(event.argumentsText, 200)}`
|
|
}
|
|
}
|
|
|
|
function formatCasePrefix(caseNumber: number, totalCases: number): string {
|
|
return `[${caseNumber}/${totalCases}]`
|
|
}
|
|
|
|
function formatDuration(durationMs: number): string {
|
|
return `${formatNumber(durationMs / 1000)}s`
|
|
}
|
|
|
|
function formatNumber(value: number): string {
|
|
return Number.isInteger(value) ? String(value) : value.toFixed(1)
|
|
}
|
|
|
|
function truncateSingleLine(value: string, maxLength: number): string {
|
|
const normalized = value.replace(/\s+/g, ' ').trim()
|
|
if (normalized.length <= maxLength) {
|
|
return normalized
|
|
}
|
|
return `${normalized.slice(0, Math.max(0, maxLength - 3))}...`
|
|
}
|