diff --git a/src/containers/AIEvals/AIEvaluationCreate/AIEvaluationCreate.module.css b/src/containers/AIEvals/AIEvaluationCreate/AIEvaluationCreate.module.css
index 39e1a4894..2e8527c3d 100644
--- a/src/containers/AIEvals/AIEvaluationCreate/AIEvaluationCreate.module.css
+++ b/src/containers/AIEvals/AIEvaluationCreate/AIEvaluationCreate.module.css
@@ -1,7 +1,3 @@
-.FormLayout {
- width: 800px;
-}
-
.GoldenQAHelper {
margin-top: 8px;
}
@@ -18,7 +14,9 @@
border: 1px dashed #7cb87c;
border-radius: 4px;
padding: 12px 16px;
- font-size: 14px;
+ font-family: monospace;
+ font-size: 13px;
+ color: #333;
}
.CSVFormatLabel {
@@ -47,11 +45,38 @@
.GoldenQaRow {
display: flex;
- align-items: flex-start;
gap: 12px;
+ align-items: center;
}
.UploadGoldenQaButton {
- margin-top: 40px;
white-space: nowrap;
+ border-radius: 20px !important;
+ flex-shrink: 0;
+ height: 40px;
+}
+
+.GoldenQaLeft {
+ width: 420px;
+ flex-shrink: 0;
+ min-width: 0;
+}
+
+.GoldenQaRight {
+ display: flex;
+ align-items: center;
+}
+
+.GoldenQaHelperText {
+ margin-top: 6px;
+}
+
+.HiddenFileInput {
+ display: none;
+}
+
+.SectionDividerLabel {
+ font-weight: 700;
+ font-size: 20px;
+ color: #191c1a;
}
diff --git a/src/containers/AIEvals/AIEvaluationCreate/AIEvaluationCreate.test.tsx b/src/containers/AIEvals/AIEvaluationCreate/AIEvaluationCreate.test.tsx
index 4db1737c3..b526cc78c 100644
--- a/src/containers/AIEvals/AIEvaluationCreate/AIEvaluationCreate.test.tsx
+++ b/src/containers/AIEvals/AIEvaluationCreate/AIEvaluationCreate.test.tsx
@@ -7,21 +7,57 @@ import {
createGoldenQaCustomSuccessMock,
createGoldenQaSuccessMock,
getAIEvaluationCreateMocks,
+ getAssistantConfigVersionsEmptyMock,
+ getAssistantConfigVersionsErrorMock,
+ getAssistantConfigVersionsLoadingMock,
+ getAssistantConfigVersionsMultipleNamesMock,
+ getAssistantConfigVersionsMock,
+ getCreateEvaluationSuccessMock,
+ getListAiEvaluationsMock,
} from 'mocks/AIEvaluations';
-import AIEvaluationCreate, { DUMMY_CREATE, DUMMY_GET_ITEM } from './AIEvaluationCreate';
+import { setNotification } from 'common/notification';
+import AIEvaluationCreate from './AIEvaluationCreate';
-const defaultMocks = getAIEvaluationCreateMocks(DUMMY_GET_ITEM, DUMMY_CREATE);
+vi.mock('common/notification', () => ({
+ setNotification: vi.fn(),
+ setErrorMessage: vi.fn(),
+}));
+
+const defaultMocks = getAIEvaluationCreateMocks();
const wrapper = (mocks: any[] = defaultMocks) => (
} />
+ Chat Page} />
);
+const fillAndSubmitForm = async (evaluationName = 'test_evaluation') => {
+ await waitFor(() => {
+ expect(screen.getByText('Create AI Evaluation')).toBeInTheDocument();
+ });
+
+ fireEvent.change(screen.getByPlaceholderText('Give a unique name for the evaluation experiment'), {
+ target: { value: evaluationName },
+ });
+
+ const assistantDropdown = screen.getAllByTestId('dropdown')[1];
+ const selectTrigger =
+ assistantDropdown.querySelector('[role="combobox"]') ?? assistantDropdown.querySelector('button');
+ fireEvent.mouseDown(selectTrigger!);
+
+ await waitFor(() => {
+ expect(screen.getByRole('option', { name: 'Test Assistant (Version 2)' })).toBeInTheDocument();
+ });
+ fireEvent.click(screen.getByRole('option', { name: 'Test Assistant (Version 2)' }));
+
+ fireEvent.click(screen.getByText('Run Evaluation'));
+};
+
describe('AIEvaluationCreate', () => {
beforeEach(() => {
vi.clearAllMocks();
@@ -70,9 +106,9 @@ describe('AIEvaluationCreate', () => {
screen.getByText(/Select the Golden QA dataset from the existing list or upload a new set/)
).toBeInTheDocument();
expect(screen.getByText('Expected CSV Format:')).toBeInTheDocument();
- expect(screen.getByText('Question,Answer')).toBeInTheDocument();
- expect(screen.getByText('What is the capital of France?,Paris')).toBeInTheDocument();
- expect(screen.getByText('Click here for the template CSV')).toBeInTheDocument();
+ expect(screen.getByText('Question, Answer')).toBeInTheDocument();
+ expect(screen.getByText('{"What Is X"},{"Answer"}')).toBeInTheDocument();
+ expect(screen.getByText('Click Here For The Template Csv')).toBeInTheDocument();
});
test('renders Upload Golden QA button', async () => {
@@ -150,10 +186,10 @@ describe('AIEvaluationCreate', () => {
render(wrapper());
await waitFor(() => {
- expect(screen.getByPlaceholderText('Give a unique name for the evaluation experiment.')).toBeInTheDocument();
+ expect(screen.getByPlaceholderText('Give a unique name for the evaluation experiment')).toBeInTheDocument();
});
- const nameInput = screen.getByPlaceholderText('Give a unique name for the evaluation experiment.');
+ const nameInput = screen.getByPlaceholderText('Give a unique name for the evaluation experiment');
fireEvent.change(nameInput, { target: { value: 'valid_name' } });
fireEvent.click(screen.getByText('Run Evaluation'));
@@ -162,43 +198,53 @@ describe('AIEvaluationCreate', () => {
});
});
- test('shows validation error for invalid evaluation name pattern', async () => {
+ test('shows validation error when evaluation name is cleared after being typed', async () => {
render(wrapper());
await waitFor(() => {
- expect(screen.getByPlaceholderText('Give a unique name for the evaluation experiment.')).toBeInTheDocument();
+ expect(screen.getByPlaceholderText('Give a unique name for the evaluation experiment')).toBeInTheDocument();
});
- const nameInput = screen.getByPlaceholderText('Give a unique name for the evaluation experiment.');
- fireEvent.change(nameInput, { target: { value: 'invalid name with spaces' } });
- fireEvent.click(screen.getByText('Run Evaluation'));
+ const nameInput = screen.getByPlaceholderText('Give a unique name for the evaluation experiment');
+ fireEvent.change(nameInput, { target: { value: 'some_name' } });
+ fireEvent.change(nameInput, { target: { value: '' } });
+ fireEvent.blur(nameInput);
await waitFor(() => {
- expect(screen.getByText('Invalid evaluation name')).toBeInTheDocument();
+ expect(screen.getByText('Evaluation name is required')).toBeInTheDocument();
});
});
- test('accepts valid evaluation name with alphanumeric, underscore and hyphen', async () => {
+ test('accepts any non-empty evaluation name', async () => {
render(wrapper());
await waitFor(() => {
- expect(screen.getByPlaceholderText('Give a unique name for the evaluation experiment.')).toBeInTheDocument();
+ expect(screen.getByPlaceholderText('Give a unique name for the evaluation experiment')).toBeInTheDocument();
});
- const nameInput = screen.getByPlaceholderText('Give a unique name for the evaluation experiment.');
+ const nameInput = screen.getByPlaceholderText('Give a unique name for the evaluation experiment');
fireEvent.change(nameInput, { target: { value: 'valid_evaluation-name123' } });
expect((nameInput as HTMLInputElement).value).toBe('valid_evaluation-name123');
});
- test('shows assistant helper text', async () => {
- render(wrapper());
+ test('shows assistant options from query using assistantName and versionNumber', async () => {
+ render(wrapper([...defaultMocks]));
await waitFor(() => {
expect(screen.getByText('Create AI Evaluation')).toBeInTheDocument();
});
- expect(screen.getByText("This list includes all assistants and versions you've created.")).toBeInTheDocument();
+ const dropdowns = screen.getAllByTestId('dropdown');
+ const assistantDropdown = dropdowns[1];
+ const selectTrigger =
+ assistantDropdown.querySelector('[role="combobox"]') ?? assistantDropdown.querySelector('button');
+ fireEvent.mouseDown(selectTrigger!);
+
+ await waitFor(() => {
+ expect(screen.getByText('Test Assistant (Version 2)')).toBeInTheDocument();
+ expect(screen.getByText('Test Assistant (Version 1)')).toBeInTheDocument();
+ });
});
test('Run Evaluation submit button is visible and enabled', async () => {
@@ -211,6 +257,137 @@ describe('AIEvaluationCreate', () => {
});
});
+ test('shows Fetching assistants... while assistant config versions are loading', async () => {
+ const mocks = [getAssistantConfigVersionsLoadingMock];
+ render(wrapper(mocks));
+
+ await waitFor(() => {
+ expect(screen.getByText('Create AI Evaluation')).toBeInTheDocument();
+ });
+
+ const dropdowns = screen.getAllByTestId('dropdown');
+ const assistantDropdown = dropdowns[1];
+ const selectTrigger =
+ assistantDropdown.querySelector('[role="combobox"]') ?? assistantDropdown.querySelector('button');
+ fireEvent.mouseDown(selectTrigger!);
+
+ await waitFor(() => {
+ expect(screen.getByText('Fetching assistants...')).toBeInTheDocument();
+ });
+ });
+
+ test('shows error notification when fetching assistant config versions fails', async () => {
+ render(wrapper([getAssistantConfigVersionsErrorMock]));
+
+ await waitFor(() => {
+ expect(setNotification).toHaveBeenCalledWith('Failed to fetch assistants', 'warning');
+ });
+ });
+
+ test('shows No assistants available when assistant config versions list is empty', async () => {
+ const mocks = [getAssistantConfigVersionsEmptyMock];
+ render(wrapper(mocks));
+
+ await waitFor(() => {
+ expect(screen.getByText('Create AI Evaluation')).toBeInTheDocument();
+ });
+
+ const dropdowns = screen.getAllByTestId('dropdown');
+ const assistantDropdown = dropdowns[1];
+ const selectTrigger =
+ assistantDropdown.querySelector('[role="combobox"]') ?? assistantDropdown.querySelector('button');
+ fireEvent.mouseDown(selectTrigger!);
+
+ await waitFor(() => {
+ expect(screen.getByText('No assistants available')).toBeInTheDocument();
+ });
+ });
+
+ test('renders assistant options in the order of their version numbers', async () => {
+ render(wrapper([getAssistantConfigVersionsMultipleNamesMock]));
+
+ await waitFor(() => {
+ expect(screen.getByText('Create AI Evaluation')).toBeInTheDocument();
+ });
+
+ const dropdowns = screen.getAllByTestId('dropdown');
+ const assistantDropdown = dropdowns[1];
+ const selectTrigger =
+ assistantDropdown.querySelector('[role="combobox"]') ?? assistantDropdown.querySelector('button');
+ fireEvent.mouseDown(selectTrigger!);
+
+ await waitFor(() => {
+ const options = screen.getAllByRole('option');
+ expect(options[0]).toHaveTextContent('Alpha Assistant (Version 1)');
+ expect(options[1]).toHaveTextContent('Beta Assistant (Version 1)');
+ expect(options[2]).toHaveTextContent('Beta Assistant (Version 2)');
+ });
+ });
+
+ test('shows all assistant config versions with correct labels for multiple assistant names', async () => {
+ const mocks = [getAssistantConfigVersionsMultipleNamesMock];
+ render(wrapper(mocks));
+
+ await waitFor(() => {
+ expect(screen.getByText('Create AI Evaluation')).toBeInTheDocument();
+ });
+
+ const dropdowns = screen.getAllByTestId('dropdown');
+ const assistantDropdown = dropdowns[1];
+ const selectTrigger =
+ assistantDropdown.querySelector('[role="combobox"]') ?? assistantDropdown.querySelector('button');
+ fireEvent.mouseDown(selectTrigger!);
+
+ await waitFor(() => {
+ expect(screen.getByText('Alpha Assistant (Version 1)')).toBeInTheDocument();
+ expect(screen.getByText('Beta Assistant (Version 1)')).toBeInTheDocument();
+ expect(screen.getByText('Beta Assistant (Version 2)')).toBeInTheDocument();
+ });
+ });
+
+ test('calls createEvaluation with correct parameters when form is submitted', async () => {
+ let capturedVariables: any = null;
+ const captureMock = {
+ request: { query: getCreateEvaluationSuccessMock.request.query },
+ variableMatcher: (vars: any) => {
+ capturedVariables = vars;
+ return true;
+ },
+ result: {
+ data: {
+ createEvaluation: {
+ __typename: 'EvaluationResult',
+ evaluation: { __typename: 'CreateEvaluationResult', status: 'queued' },
+ errors: null,
+ },
+ },
+ },
+ };
+ render(wrapper([getListAiEvaluationsMock, getAssistantConfigVersionsMock, captureMock]));
+
+ await fillAndSubmitForm('test_evaluation');
+
+ await waitFor(() => {
+ expect(capturedVariables?.input).toMatchObject({
+ datasetId: 0,
+ experimentName: 'test_evaluation',
+ configId: 'kaapi-uuid-a1',
+ configVersion: '1',
+ });
+ });
+ });
+
+ test('shows success notification and navigates to chat on successful submission', async () => {
+ render(wrapper([getListAiEvaluationsMock, getAssistantConfigVersionsMock, getCreateEvaluationSuccessMock]));
+
+ await fillAndSubmitForm();
+
+ await waitFor(() => {
+ expect(setNotification).toHaveBeenCalledWith('AI evaluation created successfully!');
+ expect(screen.getByText('Chat Page')).toBeInTheDocument();
+ });
+ });
+
test('back button is present and navigates away when clicked', async () => {
render(wrapper());
@@ -284,8 +461,8 @@ describe('AIEvaluationCreate', () => {
render(
wrapper([
...defaultMocks,
- createGoldenQaCustomSuccessMock('first_qa', 1),
- createGoldenQaCustomSuccessMock('second_qa', 1),
+ createGoldenQaCustomSuccessMock('first_qa', 1, '100'),
+ createGoldenQaCustomSuccessMock('second_qa', 1, '200'),
])
);
diff --git a/src/containers/AIEvals/AIEvaluationCreate/AIEvaluationCreate.tsx b/src/containers/AIEvals/AIEvaluationCreate/AIEvaluationCreate.tsx
index 59c30854f..c0650c79a 100644
--- a/src/containers/AIEvals/AIEvaluationCreate/AIEvaluationCreate.tsx
+++ b/src/containers/AIEvals/AIEvaluationCreate/AIEvaluationCreate.tsx
@@ -1,35 +1,17 @@
-import { gql } from '@apollo/client';
+import { useQuery } from '@apollo/client';
import { Button } from 'components/UI/Form/Button/Button';
import { Dropdown } from 'components/UI/Form/Dropdown/Dropdown';
import { Input } from 'components/UI/Form/Input/Input';
import { FormLayout } from 'containers/Form/FormLayout';
-import React, { useRef, useState } from 'react';
+import { CREATE_EVALUATION } from 'graphql/mutations/AIEvaluations';
+import { GET_ASSISTANT_CONFIG_VERSIONS } from 'graphql/queries/Assistant';
+import { useEffect, useRef, useState } from 'react';
+import { useNavigate } from 'react-router';
import * as Yup from 'yup';
+import { setNotification } from 'common/notification';
+import { UploadGoldenQaDialog } from 'containers/AIEvals/UploadGoldenQaDialog/UploadGoldenQaDialog';
import styles from './AIEvaluationCreate.module.css';
-import { UploadGoldenQaDialog } from './UploadGoldenQaDialog';
-
-// Dummy GraphQL documents until backend supports get/update/delete for AI evaluations (exported for tests)
-export const DUMMY_GET_ITEM = gql`
- query DummyAiEvalGet {
- __typename
- }
-`;
-export const DUMMY_UPDATE = gql`
- mutation DummyAiEvalUpdate {
- __typename
- }
-`;
-export const DUMMY_DELETE = gql`
- mutation DummyAiEvalDelete {
- __typename
- }
-`;
-export const DUMMY_CREATE = gql`
- mutation DummyAiEvalCreate {
- __typename
- }
-`;
const goldenQAHelperContent = (
@@ -38,36 +20,46 @@ const goldenQAHelperContent = (
evaluation on.
);
const GoldenQaField = (props: any) => {
- const { onUploadGoldenQaClick, form, ...dropdownProps } = props;
+ const { onUploadGoldenQaClick, form, helperText, ...dropdownProps } = props;
return (
-
-
-
+
+
+
+
+
+
+
+
+
+ {helperText &&
{helperText}
}
);
};
+const SectionDivider = (_props: any) => null;
+
export default function AIEvaluationCreate() {
- const [goldenQADatasets, setGoldenQADatasets] = useState
([]);
+ const navigate = useNavigate();
+ const [goldenQADatasets, setGoldenQADatasets] = useState>([]);
const [showUploadGoldenQaDialog, setShowUploadGoldenQaDialog] = useState(false);
const [selectedGoldenQaFileName, setSelectedGoldenQaFileName] = useState(null);
const [selectedGoldenQaFile, setSelectedGoldenQaFile] = useState(null);
@@ -76,20 +68,37 @@ export default function AIEvaluationCreate() {
const goldenQaOptions =
goldenQADatasets.length === 0
? [{ id: '0', label: 'No Golden QA available, upload one first' }]
- : goldenQADatasets.map((name) => ({ id: name, label: name }));
- const assistantOptions = [{ id: '', label: 'Pick your assistant & version to evaluate' }];
+ : goldenQADatasets.map(({ datasetId, name }) => ({ id: datasetId, label: name }));
+
+ const { data: versionsData, loading: versionsLoading, error: versionsError } = useQuery(
+ GET_ASSISTANT_CONFIG_VERSIONS,
+ { variables: { filter: {} }, fetchPolicy: 'network-only' }
+ );
+
+ useEffect(() => {
+ if (versionsError) {
+ setNotification(versionsError.message, 'warning');
+ }
+ }, [versionsError]);
+
+ const assistantOptions = versionsLoading
+ ? [{ id: '', label: 'Fetching assistants...' }]
+ : versionsData?.assistantConfigVersions?.length > 0
+ ? versionsData.assistantConfigVersions.map((v: any) => ({
+ id: v.id,
+ label: `${v.assistantName} (Version ${v.versionNumber})`,
+ }))
+ : [{ id: '', label: 'No assistants available' }];
const validationSchema = Yup.object().shape({
- evaluationName: Yup.string()
- .required('Evaluation name is required')
- .matches(/^[a-zA-Z0-9_-]+$/, 'Invalid evaluation name'),
+ evaluationName: Yup.string().required('Evaluation name is required'),
goldenQaId: Yup.string().required('Please select a Golden QA dataset'),
assistantId: Yup.string().required('Please select an AI Assistant'),
});
- const [states, setStates] = useState<{ evaluationName: string; goldenQaId: string; assistantId: string }>({
+ const [states, setStates] = useState<{ evaluationName: string; goldenQaId: number; assistantId: string }>({
evaluationName: '',
- goldenQaId: '0',
+ goldenQaId: 0,
assistantId: '',
});
@@ -110,10 +119,9 @@ export default function AIEvaluationCreate() {
setShowUploadGoldenQaDialog(true);
};
- const handleUploadGoldenQaProceed = (values: { name: string }) => {
- // Placeholder for when backend mutation response needs to be used further. New upload at top.
- setGoldenQADatasets((prev) => [values.name, ...prev]);
- setStates((prev) => ({ ...prev, goldenQaId: values.name }));
+ const handleUploadGoldenQaProceed = (values: { datasetId: number; name: string }) => {
+ setGoldenQADatasets((prev) => [{ datasetId: values.datasetId, name: values.name }, ...prev]);
+ setStates((prev) => ({ ...prev, goldenQaId: values.datasetId }));
setShowUploadGoldenQaDialog(false);
};
@@ -121,30 +129,45 @@ export default function AIEvaluationCreate() {
{
component: GoldenQaField,
name: 'goldenQaId',
- label: 'Select Golden QA',
+ label: Select Golden QA,
options: goldenQaOptions,
- placeholder: '',
helperText: goldenQAHelperContent,
onUploadGoldenQaClick: handleUploadGoldenQaButtonClick,
},
+ {
+ component: SectionDivider,
+ name: '__evaluationDetailsDivider',
+ label: Evaluation Details,
+ placeholder: '',
+ },
{
component: Input,
name: 'evaluationName',
type: 'text',
- label: 'Evaluation Name*',
- placeholder: 'Give a unique name for the evaluation experiment.',
+ label: Evaluation Name*,
+ placeholder: 'Give a unique name for the evaluation experiment',
},
{
component: Dropdown,
name: 'assistantId',
- label: 'AI Assistant*',
+ label: AI Assistant*,
options: assistantOptions,
- helperText: "This list includes all assistants and versions you've created.",
+ placeholder: '',
},
];
const dialogMessage = 'This action cannot be undone.';
+ const handleSetPayload = (payload: any) => {
+ const selectedVersion = versionsData?.assistantConfigVersions?.find((v: any) => v.id === payload.assistantId);
+ return {
+ datasetId: payload.goldenQaId,
+ experimentName: payload.evaluationName,
+ configId: selectedVersion?.kaapiUuid,
+ configVersion: selectedVersion?.id,
+ };
+ };
+
return (
navigate('/chat')}
/>
{showUploadGoldenQaDialog && selectedGoldenQaFileName && (
@@ -197,4 +222,4 @@ export default function AIEvaluationCreate() {
)}
);
-};
+}
diff --git a/src/containers/AIEvals/AIEvaluationCreate/UploadGoldenQaDialog.module.css b/src/containers/AIEvals/UploadGoldenQaDialog/UploadGoldenQaDialog.module.css
similarity index 100%
rename from src/containers/AIEvals/AIEvaluationCreate/UploadGoldenQaDialog.module.css
rename to src/containers/AIEvals/UploadGoldenQaDialog/UploadGoldenQaDialog.module.css
diff --git a/src/containers/AIEvals/AIEvaluationCreate/UploadGoldenQaDialog.test.tsx b/src/containers/AIEvals/UploadGoldenQaDialog/UploadGoldenQaDialog.test.tsx
similarity index 99%
rename from src/containers/AIEvals/AIEvaluationCreate/UploadGoldenQaDialog.test.tsx
rename to src/containers/AIEvals/UploadGoldenQaDialog/UploadGoldenQaDialog.test.tsx
index c523db273..360e0573a 100644
--- a/src/containers/AIEvals/AIEvaluationCreate/UploadGoldenQaDialog.test.tsx
+++ b/src/containers/AIEvals/UploadGoldenQaDialog/UploadGoldenQaDialog.test.tsx
@@ -190,6 +190,7 @@ describe('UploadGoldenQaDialog', () => {
expect(notificationSpy).toHaveBeenCalledWith('Golden QA uploaded successfully', 'success');
});
expect(onProceed).toHaveBeenCalledWith({
+ datasetId: 123,
name: 'golden_qa',
duplicationFactor: 1,
});
@@ -215,6 +216,7 @@ describe('UploadGoldenQaDialog', () => {
await waitFor(() => {
expect(onProceed).toHaveBeenCalledWith({
+ datasetId: 456,
name: 'my_custom_name',
duplicationFactor: 3,
});
diff --git a/src/containers/AIEvals/AIEvaluationCreate/UploadGoldenQaDialog.tsx b/src/containers/AIEvals/UploadGoldenQaDialog/UploadGoldenQaDialog.tsx
similarity index 96%
rename from src/containers/AIEvals/AIEvaluationCreate/UploadGoldenQaDialog.tsx
rename to src/containers/AIEvals/UploadGoldenQaDialog/UploadGoldenQaDialog.tsx
index daea71a4b..4dd35961d 100644
--- a/src/containers/AIEvals/AIEvaluationCreate/UploadGoldenQaDialog.tsx
+++ b/src/containers/AIEvals/UploadGoldenQaDialog/UploadGoldenQaDialog.tsx
@@ -13,7 +13,7 @@ export interface UploadGoldenQaDialogProps {
fileName: string;
file: File | null;
onClose: () => void;
- onProceed: (values: { name: string; duplicationFactor: number }) => void;
+ onProceed: (values: { datasetId: number; name: string; duplicationFactor: number }) => void;
}
export const UploadGoldenQaDialog = ({ open, fileName, file, onClose, onProceed }: UploadGoldenQaDialogProps) => {
@@ -94,6 +94,7 @@ export const UploadGoldenQaDialog = ({ open, fileName, file, onClose, onProceed
setNotification('Golden QA uploaded successfully', 'success');
onProceed({
+ datasetId: parseInt(goldenQa.datasetId, 10),
name: goldenQa.name,
duplicationFactor: goldenQa.duplication_factor,
});
diff --git a/src/graphql/mutations/AIEvaluations.ts b/src/graphql/mutations/AIEvaluations.ts
index 8d919c105..eb063b606 100644
--- a/src/graphql/mutations/AIEvaluations.ts
+++ b/src/graphql/mutations/AIEvaluations.ts
@@ -1,9 +1,23 @@
import { gql } from '@apollo/client';
+export const CREATE_EVALUATION = gql`
+ mutation createEvaluation($input: EvaluationInput!) {
+ createEvaluation(input: $input) {
+ evaluation {
+ status
+ }
+ errors {
+ message
+ }
+ }
+ }
+`;
+
export const CREATE_GOLDEN_QA = gql`
mutation CreateGoldenQa($input: GoldenQaInput!) {
createGoldenQa(input: $input) {
goldenQa {
+ datasetId
name
}
errors {
diff --git a/src/graphql/queries/AIEvaluations.ts b/src/graphql/queries/AIEvaluations.ts
new file mode 100644
index 000000000..40e1c5c12
--- /dev/null
+++ b/src/graphql/queries/AIEvaluations.ts
@@ -0,0 +1,24 @@
+import { gql } from '@apollo/client';
+
+export const COUNT_AI_EVALUATIONS = gql`
+ query countAiEvaluations($filter: AiEvaluationFilter) {
+ countAiEvaluations(filter: $filter)
+ }
+`;
+
+export const LIST_AI_EVALUATIONS = gql`
+ query AiEvaluations($filter: AiEvaluationFilter, $opts: Opts) {
+ aiEvaluations(filter: $filter, opts: $opts) {
+ id
+ name
+ status
+ failureReason
+ results
+ kaapiEvaluationId
+ datasetId
+ assistantConfigVersionId
+ insertedAt
+ updatedAt
+ }
+ }
+`;
diff --git a/src/graphql/queries/Assistant.ts b/src/graphql/queries/Assistant.ts
index 5fc9cab76..8266762cf 100644
--- a/src/graphql/queries/Assistant.ts
+++ b/src/graphql/queries/Assistant.ts
@@ -1,6 +1,5 @@
import { gql } from '@apollo/client';
-
/** @deprecated Use FILTER_ASSISTANTS instead */
export const GET_ASSISTANTS = gql`
query Assistants($filter: AssistantFilter, $opts: Opts) {
@@ -37,6 +36,21 @@ export const GET_ASSISTANTS_COUNT = gql`
}
`;
+export const GET_ASSISTANT_CONFIG_VERSIONS = gql`
+ query AssistantConfigVersions {
+ assistantConfigVersions {
+ id
+ assistantId
+ versionNumber
+ description
+ model
+ status
+ assistantName
+ kaapiUuid
+ }
+ }
+`;
+
export const GET_ASSISTANT = gql`
query Assistant($assistantId: ID!) {
assistant(id: $assistantId) {
diff --git a/src/mocks/AIEvaluations.ts b/src/mocks/AIEvaluations.ts
index cfe38b090..073b81d21 100644
--- a/src/mocks/AIEvaluations.ts
+++ b/src/mocks/AIEvaluations.ts
@@ -1,20 +1,140 @@
-import { CREATE_GOLDEN_QA } from 'graphql/mutations/AIEvaluations';
+import { CREATE_EVALUATION, CREATE_GOLDEN_QA } from 'graphql/mutations/AIEvaluations';
+import { LIST_AI_EVALUATIONS } from 'graphql/queries/AIEvaluations';
+import { GET_ASSISTANT_CONFIG_VERSIONS } from 'graphql/queries/Assistant';
-export const getDummyGetItemMock = (query: unknown) => ({
- request: { query },
- result: { data: { __typename: 'Query' } },
-});
+export const getListAiEvaluationsMock = {
+ request: { query: LIST_AI_EVALUATIONS, variables: { filter: {}, opts: {} } },
+ result: { data: { aiEvaluations: [] } },
+};
+
+const evaluationSuccessResult = {
+ data: {
+ createEvaluation: {
+ __typename: 'EvaluationResult',
+ evaluation: { __typename: 'CreateEvaluationResult', status: 'queued' },
+ errors: null,
+ },
+ },
+};
+
+export const getCreateEvaluationMock = {
+ request: { query: CREATE_EVALUATION },
+ result: evaluationSuccessResult,
+};
-export const getDummyCreateMock = (query: unknown) => ({
- request: { query },
- result: { data: { __typename: 'Mutation' } },
+export const getCreateEvaluationWithVariablesMock = (input: {
+ datasetId: number;
+ experimentName: string;
+ configId: string;
+ configVersion: string;
+}) => ({
+ request: { query: CREATE_EVALUATION, variables: { input } },
+ result: evaluationSuccessResult,
});
-export const getAIEvaluationCreateMocks = (getItemQuery: unknown, createQuery: unknown) => [
- getDummyGetItemMock(getItemQuery),
- getDummyCreateMock(createQuery),
+export const getCreateEvaluationSuccessMock = {
+ request: { query: CREATE_EVALUATION },
+ variableMatcher: () => true,
+ result: evaluationSuccessResult,
+};
+
+export const getAIEvaluationCreateMocks = () => [
+ getListAiEvaluationsMock,
+ getCreateEvaluationMock,
+ getAssistantConfigVersionsMock,
];
+export const getAssistantConfigVersionsMock = {
+ request: { query: GET_ASSISTANT_CONFIG_VERSIONS, variables: { filter: {} } },
+ result: {
+ data: {
+ assistantConfigVersions: [
+ {
+ __typename: 'AssistantConfigVersion',
+ id: '1',
+ assistantId: 'a1',
+ assistantName: 'Test Assistant',
+ versionNumber: 2,
+ description: 'v2 config',
+ model: 'gpt-4',
+ status: 'ACTIVE',
+ kaapiUuid: 'kaapi-uuid-a1',
+ },
+ {
+ __typename: 'AssistantConfigVersion',
+ id: '2',
+ assistantId: 'a1',
+ assistantName: 'Test Assistant',
+ versionNumber: 1,
+ description: 'v1 config',
+ model: 'gpt-4',
+ status: 'ACTIVE',
+ kaapiUuid: 'kaapi-uuid-a1-v1',
+ },
+ ],
+ },
+ },
+};
+
+export const getAssistantConfigVersionsErrorMock = {
+ request: { query: GET_ASSISTANT_CONFIG_VERSIONS, variables: { filter: {} } },
+ error: new Error('Failed to fetch assistants'),
+};
+
+export const getAssistantConfigVersionsEmptyMock = {
+ request: { query: GET_ASSISTANT_CONFIG_VERSIONS, variables: { filter: {} } },
+ result: { data: { assistantConfigVersions: [] } },
+};
+
+export const getAssistantConfigVersionsLoadingMock = {
+ request: { query: GET_ASSISTANT_CONFIG_VERSIONS, variables: { filter: {} } },
+ result: { data: { assistantConfigVersions: [] } },
+ delay: Infinity,
+};
+
+export const getAssistantConfigVersionsMultipleNamesMock = {
+ request: { query: GET_ASSISTANT_CONFIG_VERSIONS, variables: { filter: {} } },
+ result: {
+ data: {
+ assistantConfigVersions: [
+ {
+ __typename: 'AssistantConfigVersion',
+ id: '1',
+ assistantId: 'a1',
+ assistantName: 'Alpha Assistant',
+ versionNumber: 1,
+ description: 'v1',
+ model: 'gpt-4',
+ status: 'ACTIVE',
+ kaapiUuid: 'kaapi-alpha-v1',
+ },
+ {
+ __typename: 'AssistantConfigVersion',
+ id: '2',
+ assistantId: 'a2',
+ assistantName: 'Beta Assistant',
+ versionNumber: 1,
+ description: 'v3',
+ model: 'gpt-4',
+ status: 'ACTIVE',
+ kaapiUuid: 'kaapi-beta-v3',
+ },
+ {
+ __typename: 'AssistantConfigVersion',
+ id: '3',
+ assistantId: 'a2',
+ assistantName: 'Beta Assistant',
+ versionNumber: 2,
+ description: 'v1',
+ model: 'gpt-4',
+ status: 'ACTIVE',
+ kaapiUuid: 'kaapi-beta-v1',
+ },
+ ],
+ },
+ },
+};
+
export const createGoldenQaSuccessMock = {
request: { query: CREATE_GOLDEN_QA },
variableMatcher: () => true,
@@ -22,7 +142,7 @@ export const createGoldenQaSuccessMock = {
data: {
createGoldenQa: {
__typename: 'CreateGoldenQaPayload',
- goldenQa: { __typename: 'GoldenQa', name: 'golden_qa', duplication_factor: 1 },
+ goldenQa: { __typename: 'GoldenQa', datasetId: '123', name: 'golden_qa', duplication_factor: 1 },
errors: null,
},
},
@@ -49,14 +169,14 @@ export const createGoldenQaNetworkErrorMock = {
error: new Error('Network error'),
};
-export const createGoldenQaCustomSuccessMock = (name: string, duplicationFactor: number) => ({
+export const createGoldenQaCustomSuccessMock = (name: string, duplicationFactor: number, datasetId = '456') => ({
request: { query: CREATE_GOLDEN_QA },
variableMatcher: () => true,
result: {
data: {
createGoldenQa: {
__typename: 'CreateGoldenQaPayload',
- goldenQa: { __typename: 'GoldenQa', name, duplication_factor: duplicationFactor },
+ goldenQa: { __typename: 'GoldenQa', datasetId, name, duplication_factor: duplicationFactor },
errors: null,
},
},