promptfoo 0.20.0 → 0.21.0

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.
Files changed (184) hide show
  1. package/README.md +1 -1
  2. package/dist/package.json +4 -4
  3. package/dist/src/assertions.d.ts.map +1 -1
  4. package/dist/src/assertions.js +5 -0
  5. package/dist/src/assertions.js.map +1 -1
  6. package/dist/src/evaluator.js +1 -1
  7. package/dist/src/evaluator.js.map +1 -1
  8. package/dist/src/index.d.ts +1 -5
  9. package/dist/src/index.d.ts.map +1 -1
  10. package/dist/src/index.js +1 -1
  11. package/dist/src/index.js.map +1 -1
  12. package/dist/src/matchers.d.ts +3 -2
  13. package/dist/src/matchers.d.ts.map +1 -1
  14. package/dist/src/matchers.js +37 -9
  15. package/dist/src/matchers.js.map +1 -1
  16. package/dist/src/providers/anthropic.d.ts +5 -3
  17. package/dist/src/providers/anthropic.d.ts.map +1 -1
  18. package/dist/src/providers/anthropic.js +8 -10
  19. package/dist/src/providers/anthropic.js.map +1 -1
  20. package/dist/src/providers/azureopenai.d.ts +9 -8
  21. package/dist/src/providers/azureopenai.d.ts.map +1 -1
  22. package/dist/src/providers/azureopenai.js +33 -36
  23. package/dist/src/providers/azureopenai.js.map +1 -1
  24. package/dist/src/providers/openai.d.ts +12 -12
  25. package/dist/src/providers/openai.d.ts.map +1 -1
  26. package/dist/src/providers/openai.js +54 -65
  27. package/dist/src/providers/openai.js.map +1 -1
  28. package/dist/src/providers/replicate.d.ts +4 -2
  29. package/dist/src/providers/replicate.d.ts.map +1 -1
  30. package/dist/src/providers/replicate.js +10 -8
  31. package/dist/src/providers/replicate.js.map +1 -1
  32. package/dist/src/providers/webhook.d.ts +9 -0
  33. package/dist/src/providers/webhook.d.ts.map +1 -0
  34. package/dist/src/providers/webhook.js +54 -0
  35. package/dist/src/providers/webhook.js.map +1 -0
  36. package/dist/src/providers.d.ts +1 -1
  37. package/dist/src/providers.d.ts.map +1 -1
  38. package/dist/src/providers.js +36 -28
  39. package/dist/src/providers.js.map +1 -1
  40. package/dist/src/suggestions.d.ts.map +1 -1
  41. package/dist/src/suggestions.js +1 -3
  42. package/dist/src/suggestions.js.map +1 -1
  43. package/dist/src/types.d.ts +7 -1
  44. package/dist/src/types.d.ts.map +1 -1
  45. package/dist/src/util.js +1 -1
  46. package/dist/src/util.js.map +1 -1
  47. package/dist/src/web/nextui/404/index.html +1 -1
  48. package/dist/src/web/nextui/404.html +1 -1
  49. package/dist/src/web/nextui/_next/static/Bl3o5lF4ON7Fjki46lPhr/_buildManifest.js +1 -0
  50. package/dist/src/web/nextui/_next/static/chunks/226-7bbb6c98a19542fd.js +37 -0
  51. package/dist/src/web/nextui/_next/static/chunks/249-ea9c0f034888ccff.js +125 -0
  52. package/dist/src/web/nextui/_next/static/chunks/339-501c32916b785ef1.js +1 -0
  53. package/dist/src/web/nextui/_next/static/chunks/365-e426ea5bc7e815fc.js +8 -0
  54. package/dist/src/web/nextui/_next/static/chunks/396-0a51429a01e24cdd.js +1 -0
  55. package/dist/src/web/nextui/_next/static/chunks/596-297f7ff4a0436e87.js +25 -0
  56. package/dist/src/web/nextui/_next/static/chunks/613-572c22424de64659.js +1 -0
  57. package/dist/src/web/nextui/_next/static/chunks/706-ae1d3352d28419e9.js +9 -0
  58. package/dist/src/web/nextui/_next/static/chunks/891-7035926a62c1c4e0.js +1 -0
  59. package/dist/src/web/nextui/_next/static/chunks/app/eval/[id]/not-found-366629541fd598e9.js +1 -0
  60. package/dist/src/web/nextui/_next/static/chunks/app/eval/[id]/page-319d2ee38d37574e.js +1 -0
  61. package/dist/src/web/nextui/_next/static/chunks/app/eval/page-a6b1ff91723b7beb.js +1 -0
  62. package/dist/src/web/nextui/_next/static/chunks/app/layout-024c4adc71c9feb0.js +1 -0
  63. package/dist/src/web/nextui/_next/static/chunks/app/page-1ae60660130041b2.js +1 -0
  64. package/dist/src/web/nextui/_next/static/chunks/app/setup/page-6ef16148040bf4f4.js +1 -0
  65. package/dist/src/web/nextui/_next/static/chunks/{ca377847-cb6ae6a6a073aebb.js → ca377847-26b462611379a4f7.js} +3 -3
  66. package/dist/src/web/nextui/_next/static/chunks/{fd9d1056-ac777be631f5a9e9.js → fd9d1056-fba4b53a2f01213b.js} +1 -1
  67. package/dist/src/web/nextui/_next/static/chunks/framework-8883d1e9be70c3da.js +25 -0
  68. package/dist/src/web/nextui/_next/static/chunks/main-8ea85465d428ecfe.js +1 -0
  69. package/dist/src/web/nextui/_next/static/chunks/main-app-581ccf0003955b21.js +1 -0
  70. package/dist/src/web/nextui/_next/static/chunks/pages/_app-52924524f99094ab.js +1 -0
  71. package/dist/src/web/nextui/_next/static/chunks/pages/_error-c92d5c4bb2b49926.js +1 -0
  72. package/dist/src/web/nextui/_next/static/chunks/webpack-55c264ce2fd85eb7.js +1 -0
  73. package/dist/src/web/nextui/_next/static/css/4d399fceacd06992.css +1 -0
  74. package/dist/src/web/nextui/eval/index.html +1 -1
  75. package/dist/src/web/nextui/eval/index.txt +6 -6
  76. package/dist/src/web/nextui/index.html +1 -1
  77. package/dist/src/web/nextui/index.txt +5 -5
  78. package/dist/src/web/nextui/setup/index.html +27 -1
  79. package/dist/src/web/nextui/setup/index.txt +9 -9
  80. package/dist/src/web/server.d.ts.map +1 -1
  81. package/dist/src/web/server.js +9 -5
  82. package/dist/src/web/server.js.map +1 -1
  83. package/package.json +4 -4
  84. package/dist/src/web/nextui/_next/static/US6gOx8LHTX_Hzm9aYNrC/_buildManifest.js +0 -1
  85. package/dist/src/web/nextui/_next/static/chunks/339-4fc8a80fa840e771.js +0 -1
  86. package/dist/src/web/nextui/_next/static/chunks/373-8a280796c0f2d1af.js +0 -1
  87. package/dist/src/web/nextui/_next/static/chunks/583-125d32af505e9bc4.js +0 -1
  88. package/dist/src/web/nextui/_next/static/chunks/596-07e4a23a5c6cdf04.js +0 -25
  89. package/dist/src/web/nextui/_next/static/chunks/658-a62210d07dc4dcb6.js +0 -15
  90. package/dist/src/web/nextui/_next/static/chunks/707-699cbd84b259c37b.js +0 -37
  91. package/dist/src/web/nextui/_next/static/chunks/858-ceb6fa22e614492b.js +0 -125
  92. package/dist/src/web/nextui/_next/static/chunks/891-3000ea7c0a292558.js +0 -1
  93. package/dist/src/web/nextui/_next/static/chunks/app/eval/[id]/not-found-50e40614fa05600e.js +0 -1
  94. package/dist/src/web/nextui/_next/static/chunks/app/eval/[id]/page-c19c44ed1b2dfb58.js +0 -1
  95. package/dist/src/web/nextui/_next/static/chunks/app/eval/page-d4a1813b2f8c4532.js +0 -1
  96. package/dist/src/web/nextui/_next/static/chunks/app/layout-664a8d716d2d24b1.js +0 -1
  97. package/dist/src/web/nextui/_next/static/chunks/app/page-1f8ef6a00a2355f0.js +0 -1
  98. package/dist/src/web/nextui/_next/static/chunks/app/setup/page-182018a3c6397345.js +0 -1
  99. package/dist/src/web/nextui/_next/static/chunks/framework-43665103d101a22d.js +0 -25
  100. package/dist/src/web/nextui/_next/static/chunks/main-50cc0a98559591ce.js +0 -1
  101. package/dist/src/web/nextui/_next/static/chunks/main-app-c9dc13756d166550.js +0 -1
  102. package/dist/src/web/nextui/_next/static/chunks/pages/_app-6b79a29ad0d63b21.js +0 -1
  103. package/dist/src/web/nextui/_next/static/chunks/pages/_error-9aeb3e4d490fe4b8.js +0 -1
  104. package/dist/src/web/nextui/_next/static/chunks/webpack-6e474e42be502dd7.js +0 -1
  105. package/dist/src/web/nextui/_next/static/css/a35c840ac696f161.css +0 -1
  106. package/dist/src/web/nextui/api +0 -1
  107. package/src/__mocks__/esm.ts +0 -3
  108. package/src/assertions.ts +0 -580
  109. package/src/cache.ts +0 -109
  110. package/src/esm.ts +0 -13
  111. package/src/evaluator.ts +0 -500
  112. package/src/index.ts +0 -52
  113. package/src/logger.ts +0 -46
  114. package/src/main.ts +0 -442
  115. package/src/matchers.ts +0 -120
  116. package/src/onboarding.ts +0 -69
  117. package/src/prompts.ts +0 -39
  118. package/src/providers/anthropic.ts +0 -88
  119. package/src/providers/azureopenai.ts +0 -299
  120. package/src/providers/llama.ts +0 -95
  121. package/src/providers/localai.ts +0 -111
  122. package/src/providers/ollama.ts +0 -89
  123. package/src/providers/openai.ts +0 -337
  124. package/src/providers/replicate.ts +0 -99
  125. package/src/providers/scriptCompletion.ts +0 -35
  126. package/src/providers/shared.ts +0 -34
  127. package/src/providers.ts +0 -192
  128. package/src/share.ts +0 -27
  129. package/src/suggestions.ts +0 -63
  130. package/src/table.ts +0 -43
  131. package/src/tableOutput.html +0 -52
  132. package/src/telemetry.ts +0 -70
  133. package/src/types.ts +0 -299
  134. package/src/updates.ts +0 -46
  135. package/src/util.ts +0 -543
  136. package/src/web/nextui/.eslintrc.json +0 -3
  137. package/src/web/nextui/next.config.js +0 -14
  138. package/src/web/nextui/package-lock.json +0 -4644
  139. package/src/web/nextui/package.json +0 -47
  140. package/src/web/nextui/public/favicon.ico +0 -0
  141. package/src/web/nextui/public/logo.svg +0 -30
  142. package/src/web/nextui/src/app/Home.css +0 -3
  143. package/src/web/nextui/src/app/api/route.ts +0 -6
  144. package/src/web/nextui/src/app/components/DarkMode.css +0 -22
  145. package/src/web/nextui/src/app/components/DarkMode.tsx +0 -17
  146. package/src/web/nextui/src/app/components/Logo.css +0 -32
  147. package/src/web/nextui/src/app/components/Logo.tsx +0 -11
  148. package/src/web/nextui/src/app/components/PageShell.css +0 -33
  149. package/src/web/nextui/src/app/components/PageShell.tsx +0 -87
  150. package/src/web/nextui/src/app/eval/ConfigModal.tsx +0 -84
  151. package/src/web/nextui/src/app/eval/Eval.css +0 -13
  152. package/src/web/nextui/src/app/eval/Eval.tsx +0 -79
  153. package/src/web/nextui/src/app/eval/EvalOutputPromptDialog.tsx +0 -127
  154. package/src/web/nextui/src/app/eval/ResultsCharts.tsx +0 -355
  155. package/src/web/nextui/src/app/eval/ResultsTable.css +0 -179
  156. package/src/web/nextui/src/app/eval/ResultsTable.tsx +0 -503
  157. package/src/web/nextui/src/app/eval/ResultsView.tsx +0 -301
  158. package/src/web/nextui/src/app/eval/ShareModal.tsx +0 -70
  159. package/src/web/nextui/src/app/eval/[id]/not-found.tsx +0 -5
  160. package/src/web/nextui/src/app/eval/[id]/page.css +0 -9
  161. package/src/web/nextui/src/app/eval/[id]/page.tsx +0 -20
  162. package/src/web/nextui/src/app/eval/index.css +0 -0
  163. package/src/web/nextui/src/app/eval/page.tsx +0 -8
  164. package/src/web/nextui/src/app/eval/store.ts +0 -18
  165. package/src/web/nextui/src/app/eval/types.ts +0 -20
  166. package/src/web/nextui/src/app/globals.css +0 -58
  167. package/src/web/nextui/src/app/layout.tsx +0 -25
  168. package/src/web/nextui/src/app/page.tsx +0 -7
  169. package/src/web/nextui/src/app/setup/AssertsForm.tsx +0 -118
  170. package/src/web/nextui/src/app/setup/PromptDialog.tsx +0 -77
  171. package/src/web/nextui/src/app/setup/PromptsSection.tsx +0 -190
  172. package/src/web/nextui/src/app/setup/ProviderConfigDialog.tsx +0 -99
  173. package/src/web/nextui/src/app/setup/ProviderSelector.tsx +0 -149
  174. package/src/web/nextui/src/app/setup/RunTestSuiteButton.tsx +0 -88
  175. package/src/web/nextui/src/app/setup/TestCaseDialog.tsx +0 -108
  176. package/src/web/nextui/src/app/setup/TestCasesSection.tsx +0 -154
  177. package/src/web/nextui/src/app/setup/VarsForm.tsx +0 -57
  178. package/src/web/nextui/src/app/setup/page.css +0 -3
  179. package/src/web/nextui/src/app/setup/page.tsx +0 -160
  180. package/src/web/nextui/src/util/api.ts +0 -1
  181. package/src/web/nextui/src/util/store.ts +0 -53
  182. package/src/web/nextui/tsconfig.json +0 -28
  183. package/src/web/server.ts +0 -151
  184. /package/dist/src/web/nextui/_next/static/{US6gOx8LHTX_Hzm9aYNrC → Bl3o5lF4ON7Fjki46lPhr}/_ssgManifest.js +0 -0
@@ -1,77 +0,0 @@
1
- import React from 'react';
2
- import {
3
- Dialog,
4
- DialogTitle,
5
- DialogContent,
6
- DialogActions,
7
- TextField,
8
- Button,
9
- } from '@mui/material';
10
-
11
- interface PromptDialogProps {
12
- open: boolean;
13
- prompt: string;
14
- index: number;
15
- onAdd: (prompt: string) => void;
16
- onCancel: () => void;
17
- }
18
-
19
- const PromptDialog: React.FC<PromptDialogProps> = ({ open, prompt, index, onAdd, onCancel }) => {
20
- const [editingPrompt, setEditingPrompt] = React.useState(prompt);
21
- const textFieldRef = React.useRef<HTMLInputElement>(null);
22
-
23
- React.useEffect(() => {
24
- setEditingPrompt(prompt);
25
- }, [prompt]);
26
-
27
- const handleAdd = (close: boolean) => {
28
- onAdd(editingPrompt);
29
- setEditingPrompt('');
30
- if (close) {
31
- onCancel();
32
- } else if (textFieldRef.current) {
33
- textFieldRef.current.focus();
34
- }
35
- };
36
-
37
- return (
38
- <Dialog open={open} onClose={onCancel} fullWidth maxWidth="md">
39
- <DialogTitle>{`Edit Prompt ${index + 1}`}</DialogTitle>
40
- <DialogContent>
41
- <TextField
42
- value={editingPrompt}
43
- onChange={(e) => setEditingPrompt(e.target.value)}
44
- fullWidth
45
- margin="normal"
46
- multiline
47
- placeholder="The quick brown {{animal1}} jumps over the lazy {{animal2}}."
48
- helperText="Tip: use the {{varname}} syntax to add variables to your prompt."
49
- inputRef={textFieldRef}
50
- />
51
- </DialogContent>
52
- <DialogActions>
53
- <Button
54
- onClick={handleAdd.bind(null, true)}
55
- color="primary"
56
- variant="contained"
57
- disabled={!editingPrompt.length}
58
- >
59
- Add
60
- </Button>
61
- <Button
62
- onClick={handleAdd.bind(null, false)}
63
- color="primary"
64
- variant="contained"
65
- disabled={!editingPrompt.length}
66
- >
67
- Add Another
68
- </Button>
69
- <Button onClick={onCancel} color="secondary">
70
- Cancel
71
- </Button>
72
- </DialogActions>
73
- </Dialog>
74
- );
75
- };
76
-
77
- export default PromptDialog;
@@ -1,190 +0,0 @@
1
- import React, { useState, useRef, useEffect } from 'react';
2
- import Button from '@mui/material/Button';
3
- import Typography from '@mui/material/Typography';
4
- import IconButton from '@mui/material/IconButton';
5
- import Table from '@mui/material/Table';
6
- import TableBody from '@mui/material/TableBody';
7
- import TableCell from '@mui/material/TableCell';
8
- import TableContainer from '@mui/material/TableContainer';
9
- import TableRow from '@mui/material/TableRow';
10
- import Tooltip from '@mui/material/Tooltip';
11
- import Stack from '@mui/material/Stack';
12
- import Edit from '@mui/icons-material/Edit';
13
- import Delete from '@mui/icons-material/Delete';
14
- import Publish from '@mui/icons-material/Publish';
15
- import Copy from '@mui/icons-material/ContentCopy';
16
-
17
- import PromptDialog from './PromptDialog';
18
- import { useStore } from '../../util/store';
19
-
20
- const PromptsSection: React.FC = () => {
21
- const [promptDialogOpen, setPromptDialogOpen] = useState(false);
22
- const [editingPromptIndex, setEditingPromptIndex] = useState<number | null>(null);
23
-
24
- const { prompts, setPrompts } = useStore();
25
- const newPromptInputRef = useRef<HTMLInputElement>(null);
26
-
27
- useEffect(() => {
28
- if (editingPromptIndex !== null && editingPromptIndex > 0 && newPromptInputRef.current) {
29
- newPromptInputRef.current.focus();
30
- }
31
- }, [editingPromptIndex]);
32
-
33
- const handleEditPrompt = (index: number) => {
34
- setEditingPromptIndex(index);
35
- setPromptDialogOpen(true);
36
- };
37
-
38
- const handleAddPromptFromFile = (event: React.ChangeEvent<HTMLInputElement>) => {
39
- event.stopPropagation();
40
- event.preventDefault();
41
-
42
- const file = event.target.files?.[0];
43
- if (file) {
44
- const reader = new FileReader();
45
- reader.onload = (e) => {
46
- const text = e.target?.result?.toString();
47
- if (text) {
48
- setPrompts([...prompts, text]);
49
- }
50
- };
51
- reader.readAsText(file);
52
- }
53
- };
54
-
55
- const handleDuplicatePrompt = (event: React.MouseEvent, index: number) => {
56
- event.stopPropagation();
57
- const duplicatedPrompt = prompts[index];
58
- setPrompts([...prompts, duplicatedPrompt]);
59
- };
60
-
61
- const handleChangePrompt = (index: number, newPrompt: string) => {
62
- setPrompts(prompts.map((p, i) => (i === index ? newPrompt : p)));
63
- };
64
-
65
- const handleRemovePrompt = (event: React.MouseEvent, indexToRemove: number) => {
66
- event.stopPropagation();
67
-
68
- if (confirm('Are you sure you want to remove this prompt?')) {
69
- setPrompts(prompts.filter((_, index) => index !== indexToRemove));
70
- }
71
- };
72
-
73
- return (
74
- <div>
75
- <Stack direction="row" spacing={2} justifyContent="space-between">
76
- <Typography variant="h5">Prompts</Typography>
77
- <div>
78
- <label htmlFor={`file-input-add-prompt`}>
79
- <Tooltip title="Upload prompt from file">
80
- <span>
81
- <IconButton component="span">
82
- <Publish />
83
- </IconButton>
84
- <input
85
- id={`file-input-add-prompt`}
86
- type="file"
87
- accept=".txt,.md"
88
- onChange={handleAddPromptFromFile}
89
- style={{ display: 'none' }}
90
- />
91
- </span>
92
- </Tooltip>
93
- </label>
94
- <Button
95
- color="primary"
96
- onClick={() => {
97
- setPromptDialogOpen(true);
98
- }}
99
- variant="contained"
100
- >
101
- Add Prompt
102
- </Button>
103
- </div>
104
- </Stack>
105
- <TableContainer>
106
- <Table>
107
- <TableBody>
108
- {prompts.length === 0 ? (
109
- <TableRow>
110
- <TableCell colSpan={2} align="center">
111
- No prompts added yet.
112
- </TableCell>
113
- </TableRow>
114
- ) : (
115
- prompts.map((prompt, index) => (
116
- <TableRow
117
- key={index}
118
- sx={{
119
- '&:hover': {
120
- backgroundColor: 'rgba(0, 0, 0, 0.04)',
121
- cursor: 'pointer',
122
- },
123
- }}
124
- onClick={() => handleEditPrompt(index)}
125
- >
126
- <TableCell>
127
- <Typography variant="body2">
128
- {`Prompt #${index + 1}: `}
129
- {(prompt.length > 250 ? prompt.slice(0, 250) + ' ...' : prompt)
130
- .split(/({{\w+}})/g)
131
- .map((part, i) =>
132
- /{{\w+}}/g.test(part) ? (
133
- <span
134
- key={i}
135
- style={{
136
- backgroundColor: 'linen',
137
- padding: '0.25rem',
138
- borderRadius: '4px',
139
- }}
140
- >
141
- {part}
142
- </span>
143
- ) : (
144
- part
145
- ),
146
- )}
147
- </Typography>
148
- </TableCell>
149
- <TableCell align="right" sx={{ minWidth: 150 }}>
150
- <IconButton onClick={() => handleEditPrompt(index)} size="small">
151
- <Edit />
152
- </IconButton>
153
- <IconButton
154
- onClick={(event) => handleDuplicatePrompt(event, index)}
155
- size="small"
156
- >
157
- <Copy />
158
- </IconButton>
159
- <IconButton onClick={(event) => handleRemovePrompt(event, index)} size="small">
160
- <Delete />
161
- </IconButton>
162
- </TableCell>
163
- </TableRow>
164
- ))
165
- )}
166
- </TableBody>
167
- </Table>
168
- </TableContainer>
169
- <PromptDialog
170
- open={promptDialogOpen}
171
- prompt={editingPromptIndex !== null ? prompts[editingPromptIndex] : ''}
172
- index={editingPromptIndex !== null ? editingPromptIndex : 0}
173
- onAdd={(newPrompt) => {
174
- if (editingPromptIndex !== null) {
175
- handleChangePrompt(editingPromptIndex, newPrompt);
176
- } else {
177
- setPrompts([...prompts, newPrompt]);
178
- }
179
- setEditingPromptIndex(null);
180
- }}
181
- onCancel={() => {
182
- setEditingPromptIndex(null);
183
- setPromptDialogOpen(false);
184
- }}
185
- />
186
- </div>
187
- );
188
- };
189
-
190
- export default PromptsSection;
@@ -1,99 +0,0 @@
1
- import React from 'react';
2
- import {
3
- Box,
4
- Dialog,
5
- DialogTitle,
6
- DialogContent,
7
- TextField,
8
- DialogActions,
9
- Button,
10
- } from '@mui/material';
11
- import { ProviderOptions } from '../../../../../types';
12
-
13
- interface ProviderConfigDialogProps {
14
- open: boolean;
15
- providerId: string;
16
- config: ProviderOptions['config'];
17
- onClose: () => void;
18
- onSave: (config: ProviderOptions['config']) => void;
19
- }
20
-
21
- const ProviderConfigDialog: React.FC<ProviderConfigDialogProps> = ({
22
- open,
23
- providerId,
24
- config,
25
- onClose,
26
- onSave,
27
- }) => {
28
- const [localConfig, setLocalConfig] = React.useState(config);
29
-
30
- React.useEffect(() => {
31
- setLocalConfig(config);
32
- }, [config]);
33
-
34
- const handleSave = () => {
35
- onSave(localConfig);
36
- };
37
-
38
- return (
39
- <Dialog open={open} onClose={onClose}>
40
- <DialogTitle>Edit {providerId}</DialogTitle>
41
- <DialogContent>
42
- {Object.keys(localConfig).map((key) => {
43
- const value = localConfig[key];
44
- let handleChange;
45
-
46
- if (
47
- typeof value === 'number' ||
48
- typeof value === 'boolean' ||
49
- typeof value === 'string'
50
- ) {
51
- if (typeof value === 'number') {
52
- handleChange = (e: React.ChangeEvent<HTMLInputElement>) =>
53
- setLocalConfig({ ...localConfig, [key]: parseFloat(e.target.value) });
54
- } else if (typeof value === 'boolean') {
55
- handleChange = (e: React.ChangeEvent<HTMLInputElement>) =>
56
- setLocalConfig({ ...localConfig, [key]: e.target.value === 'true' });
57
- } else {
58
- handleChange = (e: React.ChangeEvent<HTMLInputElement>) =>
59
- setLocalConfig({ ...localConfig, [key]: e.target.value });
60
- }
61
-
62
- return (
63
- <Box key={key} my={2}>
64
- <TextField
65
- label={key}
66
- value={value}
67
- onChange={handleChange}
68
- fullWidth
69
- type={typeof value === 'number' ? 'number' : 'text'}
70
- />
71
- </Box>
72
- );
73
- } else {
74
- return (
75
- <Box key={key} my={2}>
76
- <TextField
77
- label={key}
78
- value={JSON.stringify(value)}
79
- onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
80
- setLocalConfig({ ...localConfig, [key]: JSON.parse(e.target.value) })
81
- }
82
- fullWidth
83
- multiline
84
- minRows={3}
85
- />
86
- </Box>
87
- );
88
- }
89
- })}
90
- </DialogContent>
91
- <DialogActions>
92
- <Button onClick={onClose}>Cancel</Button>
93
- <Button onClick={handleSave}>Save</Button>
94
- </DialogActions>
95
- </Dialog>
96
- );
97
- };
98
-
99
- export default ProviderConfigDialog;
@@ -1,149 +0,0 @@
1
- import React from 'react';
2
- import { Autocomplete, Box, Chip, TextField } from '@mui/material';
3
- import { ProviderOptions } from '../../../../../types';
4
- import ProviderConfigDialog from './ProviderConfigDialog';
5
-
6
- const defaultProviders: ProviderOptions[] = [
7
- {
8
- id: 'replicate:replicate/llama70b-v2-chat:e951f18578850b652510200860fc4ea62b3b16fac280f83ff32282f87bbd2e48',
9
- config: { temperature: 0.5 },
10
- },
11
- ]
12
- .concat(
13
- [
14
- 'anthropic:claude-1',
15
- 'anthropic:claude-1-100k',
16
- 'anthropic:claude-instant-1',
17
- 'anthropic:claude-instant-1-100k',
18
- ].map((id) => ({ id, config: { temperature: 0.5 } })),
19
- )
20
- .concat(
21
- [
22
- 'openai:gpt-3.5-turbo',
23
- 'openai:gpt-3.5-turbo-0301',
24
- 'openai:gpt-3.5-turbo-0613',
25
- 'openai:gpt-3.5-turbo-16k',
26
- 'openai:gpt-3.5-turbo-16k-0613',
27
- 'openai:gpt-4',
28
- 'openai:gpt-4-0314',
29
- 'openai:gpt-4-0613',
30
- 'openai:gpt-4-32k',
31
- 'openai:gpt-4-32k-0314',
32
- ].map((id) => ({ id, config: { temperature: 0.5, max_tokens: 1024 } })),
33
- )
34
- .concat(
35
- [
36
- 'azureopenai:gpt-3.5-turbo',
37
- 'azureopenai:gpt-3.5-turbo-0301',
38
- 'azureopenai:gpt-3.5-turbo-0613',
39
- 'azureopenai:gpt-3.5-turbo-16k',
40
- 'azureopenai:gpt-3.5-turbo-16k-0613',
41
- 'azureopenai:gpt-4',
42
- 'azureopenai:gpt-4-0314',
43
- 'azureopenai:gpt-4-0613',
44
- 'azureopenai:gpt-4-32k',
45
- 'azureopenai:gpt-4-32k-0314',
46
- ].map((id) => ({ id, config: { temperature: 0.5, max_tokens: 1024 } })),
47
- )
48
- .sort((a, b) => a.id.localeCompare(b.id));
49
-
50
- interface ProviderSelectorProps {
51
- providers: ProviderOptions[];
52
- onChange: (providers: ProviderOptions[]) => void;
53
- }
54
-
55
- const ProviderSelector: React.FC<ProviderSelectorProps> = ({ providers, onChange }) => {
56
- const [selectedProvider, setSelectedProvider] = React.useState<ProviderOptions | null>(null);
57
-
58
- const getProviderLabel = (provider: string | ProviderOptions) => {
59
- if (typeof provider === 'string') {
60
- return provider;
61
- }
62
- return provider.id || 'Unknown provider';
63
- };
64
-
65
- const getProviderKey = (provider: string | ProviderOptions, index: number) => {
66
- if (typeof provider === 'string') {
67
- return provider;
68
- }
69
- return provider.id || index;
70
- };
71
-
72
- const handleProviderClick = (provider: string | ProviderOptions) => {
73
- if (typeof provider === 'string') {
74
- alert('Cannot edit custom providers');
75
- } else if (!provider.config) {
76
- alert('There is no config for this provider');
77
- } else {
78
- setSelectedProvider(provider as ProviderOptions);
79
- }
80
- };
81
-
82
- const handleSave = (config: ProviderOptions['config']) => {
83
- if (selectedProvider) {
84
- const updatedProviders = providers.map((provider) =>
85
- provider.id === selectedProvider.id ? { ...provider, config } : provider,
86
- );
87
- onChange(updatedProviders);
88
- setSelectedProvider(null);
89
- }
90
- };
91
-
92
- return (
93
- <Box mt={2}>
94
- <Autocomplete
95
- multiple
96
- freeSolo
97
- options={defaultProviders}
98
- value={providers}
99
- onChange={(event, newValue: (string | ProviderOptions)[]) => {
100
- onChange(newValue.map((value) => (typeof value === 'string' ? { id: value } : value)));
101
- }}
102
- getOptionLabel={(option) => {
103
- if (!option) {
104
- return '';
105
- }
106
- if (typeof option === 'string') {
107
- return option;
108
- }
109
- return (option as ProviderOptions).id || 'Unknown provider';
110
- }}
111
- renderTags={(value, getTagProps) =>
112
- value.map((provider, index: number) => {
113
- const label = getProviderLabel(provider);
114
- const key = getProviderKey(provider, index);
115
-
116
- return (
117
- <Chip
118
- variant="outlined"
119
- label={label}
120
- {...getTagProps({ index })}
121
- key={key}
122
- onClick={() => handleProviderClick(provider)}
123
- />
124
- );
125
- })
126
- }
127
- renderInput={(params) => (
128
- <TextField
129
- {...params}
130
- variant="outlined"
131
- placeholder="Select LLM providers"
132
- helperText={providers.length > 0 ? 'Click a provider to configure its settings.' : null}
133
- />
134
- )}
135
- />
136
- {selectedProvider && selectedProvider.id && (
137
- <ProviderConfigDialog
138
- open={!!selectedProvider}
139
- providerId={selectedProvider.id}
140
- config={selectedProvider.config}
141
- onClose={() => setSelectedProvider(null)}
142
- onSave={handleSave}
143
- />
144
- )}
145
- </Box>
146
- );
147
- };
148
-
149
- export default ProviderSelector;
@@ -1,88 +0,0 @@
1
- 'use client';
2
-
3
- import React, { useState } from 'react';
4
- import { useRouter } from 'next/navigation';
5
- import { Button, CircularProgress } from '@mui/material';
6
-
7
- import { useStore } from '@/util/store';
8
- import { API_BASE_URL } from '@/util/api';
9
-
10
- const RunTestSuiteButton: React.FC = () => {
11
- const router = useRouter();
12
- const { description, providers, prompts, testCases } = useStore();
13
- const [isRunning, setIsRunning] = useState(false);
14
- const [progressPercent, setProgressPercent] = useState(0);
15
-
16
- const runTestSuite = async () => {
17
- setIsRunning(true);
18
-
19
- const testSuite = {
20
- description,
21
- providers,
22
- prompts,
23
- tests: testCases,
24
- };
25
-
26
- try {
27
- const response = await fetch(`${API_BASE_URL}/api/eval`, {
28
- method: 'POST',
29
- headers: {
30
- 'Content-Type': 'application/json',
31
- },
32
- body: JSON.stringify(testSuite),
33
- });
34
-
35
- if (!response.ok) {
36
- throw new Error(`HTTP error! status: ${response.status}`);
37
- }
38
-
39
- const job = await response.json();
40
-
41
- const intervalId = setInterval(async () => {
42
- const progressResponse = await fetch(`${API_BASE_URL}/api/eval/${job.id}`);
43
-
44
- if (!progressResponse.ok) {
45
- clearInterval(intervalId);
46
- throw new Error(`HTTP error! status: ${progressResponse.status}`);
47
- }
48
-
49
- const progressData = await progressResponse.json();
50
-
51
- if (progressData.status === 'completed') {
52
- clearInterval(intervalId);
53
- setIsRunning(false);
54
- router.push('/eval');
55
- } else if (progressData.status === 'failed') {
56
- clearInterval(intervalId);
57
- setIsRunning(false);
58
- throw new Error('Job failed');
59
- } else {
60
- const percent =
61
- progressData.total === 0
62
- ? 0
63
- : Math.round((progressData.progress / progressData.total) * 100);
64
- setProgressPercent(percent);
65
- }
66
- }, 1000);
67
- } catch (error) {
68
- console.error(error);
69
- setIsRunning(false);
70
- alert(`An error occurred: ${(error as Error).message}`);
71
- }
72
- };
73
-
74
- return (
75
- <Button variant="contained" color="primary" onClick={runTestSuite} disabled={isRunning}>
76
- {isRunning ? (
77
- <>
78
- <CircularProgress size={24} sx={{ marginRight: 2 }} />
79
- {progressPercent.toFixed(0)}% complete
80
- </>
81
- ) : (
82
- 'Run Evaluation'
83
- )}
84
- </Button>
85
- );
86
- };
87
-
88
- export default RunTestSuiteButton;