Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions frontend/src/components/Chat/ObjectiveHeader.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,27 @@ describe('ObjectiveHeader', () => {
expect(screen.getByRole('group', { name: 'Automated score', exact: true })).toHaveTextContent(label)
})

it.each([
{ scoreType: 'float_scale', value: '0' },
{ scoreType: 'float_scale', value: '0.9' },
{ scoreType: 'unknown', value: 'unknown' },
{ scoreType: 'unknown', value: 'true' },
])('shows a $scoreType score of $value as its raw value, not a verdict', async ({ scoreType, value }) => {
const user = userEvent.setup()
const score: BackendScore = {
id: 'score', message_piece_id: 'response', scorer_type: 'Judge', score_type: scoreType,
score_value: value, status: 'complete', timestamp: '',
}
render(<TestWrapper><ObjectiveHeader objective="Goal" automatedScore={score} /></TestWrapper>)
await user.click(screen.getByRole('button', { name: /^objective achieved outcome:/i }))
const scoreRow = screen.getByRole('group', { name: 'Automated score', exact: true })
expect(scoreRow).toHaveTextContent(value)
expect(scoreRow).not.toHaveTextContent(/Success|Failure|Undetermined/)
expect(screen.getByRole('button', { name: new RegExp(`^${value} automated score`) })).toBeInTheDocument()
// A score without a verdict must not preselect one for the human reviewer either.
expect(screen.getByRole('radio', { name: 'Success' })).toBeChecked()
})

it('retains the API explanation when scorer selection fails', async () => {
const user = userEvent.setup()
const explanation = 'The selected scorer changed. Reload the registry before selecting it again.'
Expand Down
13 changes: 10 additions & 3 deletions frontend/src/components/Chat/ObjectiveHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,12 @@ interface ObjectiveHeaderProps {
applyStatus?: ApplyScorerStatus | null
}

/** The only score type whose value answers "was the objective met?". */
const BOOLEAN_SCORE_TYPE = 'true_false'

function scoreVerdict(score?: BackendScore | null): 'success' | 'failure' | 'undetermined' {
if (!score?.score_value) return 'undetermined'
// A float_scale or unknown value is a measurement, not a verdict, so it gets none.
if (!score?.score_value || score.score_type !== BOOLEAN_SCORE_TYPE) return 'undetermined'
return score.score_value.toLowerCase() === 'true' ? 'success' : 'failure'
}

Expand All @@ -97,9 +101,12 @@ const RESULT_POPOVER_POSITIONING = {
} as const

function scoreLabel(score?: BackendScore | null): string {
const verdict = scoreVerdict(score)
if (!score) return 'Not set'
return verdict === 'undetermined' ? 'Undetermined' : verdict === 'success' ? 'Success' : 'Failure'
if (!score.score_value) return 'Undetermined'
const verdict = scoreVerdict(score)
// Nonboolean scores carry no verdict: show what the scorer recorded, as the message score does.
if (verdict === 'undetermined') return score.score_value
return verdict === 'success' ? 'Success' : 'Failure'
}

export default function ObjectiveHeader({
Expand Down
Loading