@botpress/vai 0.0.1 → 0.0.2
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/dist/assertions/check.js +23 -0
- package/dist/assertions/extension.js +36 -0
- package/dist/assertions/extract.js +27 -0
- package/dist/assertions/filter.js +70 -0
- package/dist/assertions/rate.js +33 -0
- package/dist/context.js +44 -0
- package/dist/hooks/setEvaluator.js +10 -0
- package/dist/hooks/setupClient.js +5 -0
- package/dist/index.d.ts +21 -21
- package/dist/index.js +8 -473
- package/dist/models.js +388 -0
- package/dist/scripts/update-models.js +58 -0
- package/dist/scripts/update-types.js +42 -0
- package/dist/task/compare.js +45 -0
- package/dist/utils/asyncAssertion.js +37 -0
- package/dist/utils/deferred.js +15 -0
- package/dist/utils/predictJson.js +75 -0
- package/package.json +9 -7
- package/tsup.config.ts +3 -9
- package/dist/index.cjs +0 -503
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -473
- package/dist/index.js.map +0 -1
package/dist/models.js
ADDED
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
export const Models = [
|
|
3
|
+
{
|
|
4
|
+
"id": "anthropic__claude-3-haiku-20240307",
|
|
5
|
+
"name": "Claude 3 Haiku",
|
|
6
|
+
"integration": "anthropic",
|
|
7
|
+
"input": {
|
|
8
|
+
"maxTokens": 2e5
|
|
9
|
+
},
|
|
10
|
+
"output": {
|
|
11
|
+
"maxTokens": 4096
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"id": "anthropic__claude-3-5-sonnet-20240620",
|
|
16
|
+
"name": "Claude 3.5 Sonnet",
|
|
17
|
+
"integration": "anthropic",
|
|
18
|
+
"input": {
|
|
19
|
+
"maxTokens": 2e5
|
|
20
|
+
},
|
|
21
|
+
"output": {
|
|
22
|
+
"maxTokens": 4096
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "cerebras__llama3.1-70b",
|
|
27
|
+
"name": "Llama 3.1 70B",
|
|
28
|
+
"integration": "cerebras",
|
|
29
|
+
"input": {
|
|
30
|
+
"maxTokens": 8192
|
|
31
|
+
},
|
|
32
|
+
"output": {
|
|
33
|
+
"maxTokens": 8192
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": "cerebras__llama3.1-8b",
|
|
38
|
+
"name": "Llama 3.1 8B",
|
|
39
|
+
"integration": "cerebras",
|
|
40
|
+
"input": {
|
|
41
|
+
"maxTokens": 8192
|
|
42
|
+
},
|
|
43
|
+
"output": {
|
|
44
|
+
"maxTokens": 8192
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"id": "fireworks-ai__accounts/fireworks/models/deepseek-coder-v2-instruct",
|
|
49
|
+
"name": "DeepSeek Coder V2 Instruct",
|
|
50
|
+
"integration": "fireworks-ai",
|
|
51
|
+
"input": {
|
|
52
|
+
"maxTokens": 131072
|
|
53
|
+
},
|
|
54
|
+
"output": {
|
|
55
|
+
"maxTokens": 131072
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"id": "fireworks-ai__accounts/fireworks/models/deepseek-coder-v2-lite-instruct",
|
|
60
|
+
"name": "DeepSeek Coder V2 Lite",
|
|
61
|
+
"integration": "fireworks-ai",
|
|
62
|
+
"input": {
|
|
63
|
+
"maxTokens": 163840
|
|
64
|
+
},
|
|
65
|
+
"output": {
|
|
66
|
+
"maxTokens": 163840
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"id": "fireworks-ai__accounts/fireworks/models/firellava-13b",
|
|
71
|
+
"name": "FireLLaVA-13B",
|
|
72
|
+
"integration": "fireworks-ai",
|
|
73
|
+
"input": {
|
|
74
|
+
"maxTokens": 4096
|
|
75
|
+
},
|
|
76
|
+
"output": {
|
|
77
|
+
"maxTokens": 4096
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"id": "fireworks-ai__accounts/fireworks/models/firefunction-v2",
|
|
82
|
+
"name": "Firefunction V2",
|
|
83
|
+
"integration": "fireworks-ai",
|
|
84
|
+
"input": {
|
|
85
|
+
"maxTokens": 8192
|
|
86
|
+
},
|
|
87
|
+
"output": {
|
|
88
|
+
"maxTokens": 8192
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"id": "fireworks-ai__accounts/fireworks/models/gemma2-9b-it",
|
|
93
|
+
"name": "Gemma 2 9B Instruct",
|
|
94
|
+
"integration": "fireworks-ai",
|
|
95
|
+
"input": {
|
|
96
|
+
"maxTokens": 8192
|
|
97
|
+
},
|
|
98
|
+
"output": {
|
|
99
|
+
"maxTokens": 8192
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"id": "fireworks-ai__accounts/fireworks/models/llama-v3p1-405b-instruct",
|
|
104
|
+
"name": "Llama 3.1 405B Instruct",
|
|
105
|
+
"integration": "fireworks-ai",
|
|
106
|
+
"input": {
|
|
107
|
+
"maxTokens": 131072
|
|
108
|
+
},
|
|
109
|
+
"output": {
|
|
110
|
+
"maxTokens": 131072
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"id": "fireworks-ai__accounts/fireworks/models/llama-v3p1-70b-instruct",
|
|
115
|
+
"name": "Llama 3.1 70B Instruct",
|
|
116
|
+
"integration": "fireworks-ai",
|
|
117
|
+
"input": {
|
|
118
|
+
"maxTokens": 131072
|
|
119
|
+
},
|
|
120
|
+
"output": {
|
|
121
|
+
"maxTokens": 131072
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"id": "fireworks-ai__accounts/fireworks/models/llama-v3p1-8b-instruct",
|
|
126
|
+
"name": "Llama 3.1 8B Instruct",
|
|
127
|
+
"integration": "fireworks-ai",
|
|
128
|
+
"input": {
|
|
129
|
+
"maxTokens": 131072
|
|
130
|
+
},
|
|
131
|
+
"output": {
|
|
132
|
+
"maxTokens": 131072
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"id": "fireworks-ai__accounts/fireworks/models/mixtral-8x22b-instruct",
|
|
137
|
+
"name": "Mixtral MoE 8x22B Instruct",
|
|
138
|
+
"integration": "fireworks-ai",
|
|
139
|
+
"input": {
|
|
140
|
+
"maxTokens": 65536
|
|
141
|
+
},
|
|
142
|
+
"output": {
|
|
143
|
+
"maxTokens": 65536
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"id": "fireworks-ai__accounts/fireworks/models/mixtral-8x7b-instruct",
|
|
148
|
+
"name": "Mixtral MoE 8x7B Instruct",
|
|
149
|
+
"integration": "fireworks-ai",
|
|
150
|
+
"input": {
|
|
151
|
+
"maxTokens": 32768
|
|
152
|
+
},
|
|
153
|
+
"output": {
|
|
154
|
+
"maxTokens": 32768
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"id": "fireworks-ai__accounts/fireworks/models/mythomax-l2-13b",
|
|
159
|
+
"name": "MythoMax L2 13b",
|
|
160
|
+
"integration": "fireworks-ai",
|
|
161
|
+
"input": {
|
|
162
|
+
"maxTokens": 4096
|
|
163
|
+
},
|
|
164
|
+
"output": {
|
|
165
|
+
"maxTokens": 4096
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"id": "fireworks-ai__accounts/fireworks/models/qwen2-72b-instruct",
|
|
170
|
+
"name": "Qwen2 72b Instruct",
|
|
171
|
+
"integration": "fireworks-ai",
|
|
172
|
+
"input": {
|
|
173
|
+
"maxTokens": 32768
|
|
174
|
+
},
|
|
175
|
+
"output": {
|
|
176
|
+
"maxTokens": 32768
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"id": "groq__gemma2-9b-it",
|
|
181
|
+
"name": "Gemma2 9B",
|
|
182
|
+
"integration": "groq",
|
|
183
|
+
"input": {
|
|
184
|
+
"maxTokens": 8192
|
|
185
|
+
},
|
|
186
|
+
"output": {
|
|
187
|
+
"maxTokens": 8192
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"id": "groq__llama3-70b-8192",
|
|
192
|
+
"name": "LLaMA 3 70B",
|
|
193
|
+
"integration": "groq",
|
|
194
|
+
"input": {
|
|
195
|
+
"maxTokens": 8192
|
|
196
|
+
},
|
|
197
|
+
"output": {
|
|
198
|
+
"maxTokens": 8192
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"id": "groq__llama3-8b-8192",
|
|
203
|
+
"name": "LLaMA 3 8B",
|
|
204
|
+
"integration": "groq",
|
|
205
|
+
"input": {
|
|
206
|
+
"maxTokens": 8192
|
|
207
|
+
},
|
|
208
|
+
"output": {
|
|
209
|
+
"maxTokens": 8192
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
"id": "groq__llama-3.1-70b-versatile",
|
|
214
|
+
"name": "LLaMA 3.1 70B",
|
|
215
|
+
"integration": "groq",
|
|
216
|
+
"input": {
|
|
217
|
+
"maxTokens": 128e3
|
|
218
|
+
},
|
|
219
|
+
"output": {
|
|
220
|
+
"maxTokens": 8192
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"id": "groq__llama-3.1-8b-instant",
|
|
225
|
+
"name": "LLaMA 3.1 8B",
|
|
226
|
+
"integration": "groq",
|
|
227
|
+
"input": {
|
|
228
|
+
"maxTokens": 128e3
|
|
229
|
+
},
|
|
230
|
+
"output": {
|
|
231
|
+
"maxTokens": 8192
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
"id": "groq__llama-3.2-11b-vision-preview",
|
|
236
|
+
"name": "LLaMA 3.2 11B Vision",
|
|
237
|
+
"integration": "groq",
|
|
238
|
+
"input": {
|
|
239
|
+
"maxTokens": 128e3
|
|
240
|
+
},
|
|
241
|
+
"output": {
|
|
242
|
+
"maxTokens": 8192
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"id": "groq__llama-3.2-1b-preview",
|
|
247
|
+
"name": "LLaMA 3.2 1B",
|
|
248
|
+
"integration": "groq",
|
|
249
|
+
"input": {
|
|
250
|
+
"maxTokens": 128e3
|
|
251
|
+
},
|
|
252
|
+
"output": {
|
|
253
|
+
"maxTokens": 8192
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
"id": "groq__llama-3.2-3b-preview",
|
|
258
|
+
"name": "LLaMA 3.2 3B",
|
|
259
|
+
"integration": "groq",
|
|
260
|
+
"input": {
|
|
261
|
+
"maxTokens": 128e3
|
|
262
|
+
},
|
|
263
|
+
"output": {
|
|
264
|
+
"maxTokens": 8192
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"id": "groq__llama-3.2-90b-vision-preview",
|
|
269
|
+
"name": "LLaMA 3.2 90B Vision",
|
|
270
|
+
"integration": "groq",
|
|
271
|
+
"input": {
|
|
272
|
+
"maxTokens": 128e3
|
|
273
|
+
},
|
|
274
|
+
"output": {
|
|
275
|
+
"maxTokens": 8192
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"id": "groq__llama-3.3-70b-versatile",
|
|
280
|
+
"name": "LLaMA 3.3 70B",
|
|
281
|
+
"integration": "groq",
|
|
282
|
+
"input": {
|
|
283
|
+
"maxTokens": 128e3
|
|
284
|
+
},
|
|
285
|
+
"output": {
|
|
286
|
+
"maxTokens": 32768
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"id": "groq__mixtral-8x7b-32768",
|
|
291
|
+
"name": "Mixtral 8x7B",
|
|
292
|
+
"integration": "groq",
|
|
293
|
+
"input": {
|
|
294
|
+
"maxTokens": 32768
|
|
295
|
+
},
|
|
296
|
+
"output": {
|
|
297
|
+
"maxTokens": 32768
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"id": "openai__o1-2024-12-17",
|
|
302
|
+
"name": "GPT o1",
|
|
303
|
+
"integration": "openai",
|
|
304
|
+
"input": {
|
|
305
|
+
"maxTokens": 2e5
|
|
306
|
+
},
|
|
307
|
+
"output": {
|
|
308
|
+
"maxTokens": 1e5
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
"id": "openai__o1-mini-2024-09-12",
|
|
313
|
+
"name": "GPT o1-mini",
|
|
314
|
+
"integration": "openai",
|
|
315
|
+
"input": {
|
|
316
|
+
"maxTokens": 128e3
|
|
317
|
+
},
|
|
318
|
+
"output": {
|
|
319
|
+
"maxTokens": 65536
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
"id": "openai__gpt-3.5-turbo-0125",
|
|
324
|
+
"name": "GPT-3.5 Turbo",
|
|
325
|
+
"integration": "openai",
|
|
326
|
+
"input": {
|
|
327
|
+
"maxTokens": 128e3
|
|
328
|
+
},
|
|
329
|
+
"output": {
|
|
330
|
+
"maxTokens": 4096
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
"id": "openai__gpt-4-turbo-2024-04-09",
|
|
335
|
+
"name": "GPT-4 Turbo",
|
|
336
|
+
"integration": "openai",
|
|
337
|
+
"input": {
|
|
338
|
+
"maxTokens": 128e3
|
|
339
|
+
},
|
|
340
|
+
"output": {
|
|
341
|
+
"maxTokens": 4096
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
"id": "openai__gpt-4o-2024-08-06",
|
|
346
|
+
"name": "GPT-4o (August 2024)",
|
|
347
|
+
"integration": "openai",
|
|
348
|
+
"input": {
|
|
349
|
+
"maxTokens": 128e3
|
|
350
|
+
},
|
|
351
|
+
"output": {
|
|
352
|
+
"maxTokens": 16384
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
"id": "openai__gpt-4o-2024-05-13",
|
|
357
|
+
"name": "GPT-4o (May 2024)",
|
|
358
|
+
"integration": "openai",
|
|
359
|
+
"input": {
|
|
360
|
+
"maxTokens": 128e3
|
|
361
|
+
},
|
|
362
|
+
"output": {
|
|
363
|
+
"maxTokens": 4096
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
"id": "openai__gpt-4o-2024-11-20",
|
|
368
|
+
"name": "GPT-4o (November 2024)",
|
|
369
|
+
"integration": "openai",
|
|
370
|
+
"input": {
|
|
371
|
+
"maxTokens": 128e3
|
|
372
|
+
},
|
|
373
|
+
"output": {
|
|
374
|
+
"maxTokens": 16384
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
"id": "openai__gpt-4o-mini-2024-07-18",
|
|
379
|
+
"name": "GPT-4o Mini",
|
|
380
|
+
"integration": "openai",
|
|
381
|
+
"input": {
|
|
382
|
+
"maxTokens": 128e3
|
|
383
|
+
},
|
|
384
|
+
"output": {
|
|
385
|
+
"maxTokens": 16384
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
];
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
import { Client } from "@botpress/client";
|
|
3
|
+
import _ from "lodash";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
const LLM_LIST_MODELS = "listLanguageModels";
|
|
6
|
+
const client = new Client({
|
|
7
|
+
apiUrl: process.env.CLOUD_API_ENDPOINT,
|
|
8
|
+
botId: process.env.CLOUD_BOT_ID,
|
|
9
|
+
token: process.env.CLOUD_PAT
|
|
10
|
+
});
|
|
11
|
+
const { bot } = await client.getBot({
|
|
12
|
+
id: process.env.CLOUD_BOT_ID
|
|
13
|
+
});
|
|
14
|
+
const models = [];
|
|
15
|
+
for (const integrationId in bot.integrations) {
|
|
16
|
+
const botIntegration = bot.integrations[integrationId];
|
|
17
|
+
if (botIntegration?.public && botIntegration?.enabled && botIntegration?.status === "registered") {
|
|
18
|
+
try {
|
|
19
|
+
const { integration } = await client.getPublicIntegrationById({
|
|
20
|
+
id: botIntegration.id
|
|
21
|
+
});
|
|
22
|
+
const canListModels = Object.keys(integration.actions).includes(LLM_LIST_MODELS);
|
|
23
|
+
if (!canListModels) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const { output } = await client.callAction({
|
|
27
|
+
type: `${integration.name}:${LLM_LIST_MODELS}`,
|
|
28
|
+
input: {}
|
|
29
|
+
});
|
|
30
|
+
if (_.isArray(output?.models)) {
|
|
31
|
+
for (const model of output.models) {
|
|
32
|
+
models.push({
|
|
33
|
+
id: `${integration.name}__${model.id}`,
|
|
34
|
+
name: model.name,
|
|
35
|
+
integration: integration.name,
|
|
36
|
+
input: { maxTokens: model.input.maxTokens },
|
|
37
|
+
output: { maxTokens: model.output.maxTokens }
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
} catch (err) {
|
|
42
|
+
console.error("Error fetching integration:", err instanceof Error ? err.message : `${err}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const content = JSON.stringify(_.orderBy(models, ["integration", "name"]), null, 2);
|
|
47
|
+
fs.writeFileSync(
|
|
48
|
+
"./src/models.ts",
|
|
49
|
+
`
|
|
50
|
+
// This file is generated. Do not edit it manually.
|
|
51
|
+
// See 'scripts/update-models.ts'
|
|
52
|
+
|
|
53
|
+
/* eslint-disable */
|
|
54
|
+
/* tslint:disable */
|
|
55
|
+
|
|
56
|
+
export const Models = ${content} as const`,
|
|
57
|
+
"utf-8"
|
|
58
|
+
);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
import { Client } from "@botpress/client";
|
|
3
|
+
import { z } from "@bpinternal/zui";
|
|
4
|
+
import _ from "lodash";
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
const Interfaces = ["llm"];
|
|
8
|
+
const client = new Client({
|
|
9
|
+
apiUrl: process.env.CLOUD_API_ENDPOINT,
|
|
10
|
+
botId: process.env.CLOUD_BOT_ID,
|
|
11
|
+
token: process.env.CLOUD_PAT
|
|
12
|
+
});
|
|
13
|
+
for (const name of Interfaces) {
|
|
14
|
+
const { interfaces } = await client.listInterfaces({
|
|
15
|
+
name
|
|
16
|
+
});
|
|
17
|
+
const { interface: latest } = await client.getInterface({
|
|
18
|
+
id: _.maxBy(interfaces, "version").id
|
|
19
|
+
});
|
|
20
|
+
for (const action of Object.keys(latest.actions)) {
|
|
21
|
+
const references = Object.keys(latest.entities).reduce((acc, key) => {
|
|
22
|
+
return { ...acc, [key]: z.fromJsonSchema(latest.entities?.[key]?.schema) };
|
|
23
|
+
}, {});
|
|
24
|
+
const input = latest.actions[action]?.input.schema;
|
|
25
|
+
const output = latest.actions[action]?.output.schema;
|
|
26
|
+
const types = `
|
|
27
|
+
// This file is generated. Do not edit it manually.
|
|
28
|
+
// See 'scripts/update-models.ts'
|
|
29
|
+
|
|
30
|
+
/* eslint-disable */
|
|
31
|
+
/* tslint:disable */
|
|
32
|
+
|
|
33
|
+
export namespace ${name} {
|
|
34
|
+
export namespace ${action} {
|
|
35
|
+
export ${z.fromJsonSchema(input).title("Input").dereference(references).toTypescript({ declaration: "type" })};
|
|
36
|
+
export ${z.fromJsonSchema(output).title("Output").dereference(references).toTypescript({ declaration: "type" })};
|
|
37
|
+
}
|
|
38
|
+
}`;
|
|
39
|
+
fs.mkdirSync(path.resolve(`./src/sdk-interfaces/${name}`), { recursive: true });
|
|
40
|
+
fs.writeFileSync(path.resolve(`./src/sdk-interfaces/${name}/${action}.ts`), types);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
import { z } from "@bpinternal/zui";
|
|
3
|
+
import { createTaskCollector, getCurrentSuite } from "vitest/suite";
|
|
4
|
+
import { Deferred } from "../utils/deferred";
|
|
5
|
+
const scenarioId = z.string().trim().min(1, "Scenario ID/name must not be empty").max(50, "Scenario ID/name is too long");
|
|
6
|
+
const ScenarioLike = z.union([
|
|
7
|
+
scenarioId,
|
|
8
|
+
z.object({ name: scenarioId }).passthrough(),
|
|
9
|
+
z.object({ id: scenarioId }).passthrough()
|
|
10
|
+
]);
|
|
11
|
+
const getScenarioName = (scenario) => typeof scenario === "string" ? scenario : "name" in scenario ? scenario?.name : scenario?.id;
|
|
12
|
+
const scenarioArgs = z.array(ScenarioLike).min(2, "You need at least two scenarios to compare").max(10, "You can only compare up to 10 scenarios").refine((scenarios) => {
|
|
13
|
+
const set = /* @__PURE__ */ new Set();
|
|
14
|
+
scenarios.forEach((scenario) => set.add(getScenarioName(scenario)));
|
|
15
|
+
return set.size === scenarios.length;
|
|
16
|
+
}, "Scenarios names must be unique");
|
|
17
|
+
export function compare(name, scenarios, fn) {
|
|
18
|
+
scenarios = scenarioArgs.parse(scenarios);
|
|
19
|
+
return createTaskCollector((_name, fn2, timeout) => {
|
|
20
|
+
const currentSuite = getCurrentSuite();
|
|
21
|
+
let completedCount = 0;
|
|
22
|
+
const finished = new Deferred();
|
|
23
|
+
for (const scenario of scenarios) {
|
|
24
|
+
const key = getScenarioName(scenario);
|
|
25
|
+
currentSuite.task(key, {
|
|
26
|
+
meta: {
|
|
27
|
+
scenario: key,
|
|
28
|
+
isVaiTest: true
|
|
29
|
+
},
|
|
30
|
+
handler: async (context) => {
|
|
31
|
+
const extendedContext = Object.freeze({
|
|
32
|
+
scenario
|
|
33
|
+
});
|
|
34
|
+
context.onTestFinished(() => {
|
|
35
|
+
if (++completedCount === scenarios.length) {
|
|
36
|
+
finished.resolve();
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
await fn2({ ...context, ...extendedContext });
|
|
40
|
+
},
|
|
41
|
+
timeout: timeout ?? 1e4
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
})(name, fn);
|
|
45
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
import { expect } from "vitest";
|
|
3
|
+
import { getCurrentTest } from "vitest/suite";
|
|
4
|
+
import { Context } from "../context";
|
|
5
|
+
export class AsyncExpectError extends Error {
|
|
6
|
+
constructor(message, output) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.output = output;
|
|
9
|
+
this.name = "AsyncExpectError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const getErrorMessages = (e) => {
|
|
13
|
+
if (e instanceof Error) {
|
|
14
|
+
return e.message;
|
|
15
|
+
} else if (typeof e === "string") {
|
|
16
|
+
return e;
|
|
17
|
+
} else if (typeof e === "object" && e !== null) {
|
|
18
|
+
return JSON.stringify(e);
|
|
19
|
+
}
|
|
20
|
+
return `Unknown error: ${e}`;
|
|
21
|
+
};
|
|
22
|
+
export const asyncExpect = (output, assertion) => {
|
|
23
|
+
const promise = output.then((x) => {
|
|
24
|
+
try {
|
|
25
|
+
assertion(expect(x.result, x.reason));
|
|
26
|
+
} catch (e) {
|
|
27
|
+
if (Context.wrapError) {
|
|
28
|
+
return new AsyncExpectError(getErrorMessages(e), x);
|
|
29
|
+
}
|
|
30
|
+
throw e;
|
|
31
|
+
}
|
|
32
|
+
return x;
|
|
33
|
+
});
|
|
34
|
+
getCurrentTest().promises ??= [];
|
|
35
|
+
getCurrentTest().promises.push(promise);
|
|
36
|
+
return promise;
|
|
37
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
export class Deferred {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.promise = new Promise((resolve, reject) => {
|
|
5
|
+
this._resolve = resolve;
|
|
6
|
+
this._reject = reject;
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
resolve(value) {
|
|
10
|
+
this._resolve(value);
|
|
11
|
+
}
|
|
12
|
+
reject(reason) {
|
|
13
|
+
this._reject(reason);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
import { z } from "@bpinternal/zui";
|
|
3
|
+
import JSON5 from "json5";
|
|
4
|
+
import { Context } from "../context";
|
|
5
|
+
const nonEmptyString = z.string().trim().min(1);
|
|
6
|
+
const nonEmptyObject = z.object({}).passthrough().refine((value) => Object.keys(value).length > 0, {
|
|
7
|
+
message: "Expected a non-empty object"
|
|
8
|
+
});
|
|
9
|
+
const Input = nonEmptyString.or(nonEmptyObject).or(z.array(z.any()));
|
|
10
|
+
const Output = z.object({
|
|
11
|
+
reason: nonEmptyString.describe("A human-readable explanation of the result"),
|
|
12
|
+
result: z.any().describe(
|
|
13
|
+
"Your best guess at the output according to the instructions provided, rooted in the context of the input and the reason above"
|
|
14
|
+
)
|
|
15
|
+
});
|
|
16
|
+
const Example = z.object({
|
|
17
|
+
input: Input,
|
|
18
|
+
output: Output
|
|
19
|
+
});
|
|
20
|
+
const Options = z.object({
|
|
21
|
+
systemMessage: z.string(),
|
|
22
|
+
examples: z.array(Example).default([]),
|
|
23
|
+
input: Input,
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
25
|
+
outputSchema: z.custom((value) => typeof value === "object" && value !== null && "_def" in value),
|
|
26
|
+
model: z.string()
|
|
27
|
+
});
|
|
28
|
+
const isValidExample = (outputSchema) => (example) => Input.safeParse(example.input).success && Output.safeParse(example.output).success && outputSchema.safeParse(example.output.result).success;
|
|
29
|
+
export async function predictJson(_options) {
|
|
30
|
+
const options = Options.parse(_options);
|
|
31
|
+
const [integration, model] = options.model.split("__");
|
|
32
|
+
if (!model?.length) {
|
|
33
|
+
throw new Error("Invalid model");
|
|
34
|
+
}
|
|
35
|
+
const exampleMessages = options.examples.filter(isValidExample(options.outputSchema)).flatMap(({ input, output: output2 }) => [
|
|
36
|
+
{ role: "user", content: JSON.stringify(input, null, 2) },
|
|
37
|
+
{ role: "assistant", content: JSON.stringify(output2, null, 2) }
|
|
38
|
+
]);
|
|
39
|
+
const outputSchema = Output.extend({
|
|
40
|
+
result: options.outputSchema.describe(Output.shape.result.description)
|
|
41
|
+
});
|
|
42
|
+
const result = await Context.client.callAction({
|
|
43
|
+
type: `${integration}:generateContent`,
|
|
44
|
+
input: {
|
|
45
|
+
systemPrompt: `
|
|
46
|
+
${options.systemMessage}
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
Please generate a JSON response with the following format:
|
|
50
|
+
\`\`\`typescript
|
|
51
|
+
${await outputSchema.toTypescriptAsync()}
|
|
52
|
+
\`\`\`
|
|
53
|
+
`.trim(),
|
|
54
|
+
messages: [
|
|
55
|
+
...exampleMessages,
|
|
56
|
+
{
|
|
57
|
+
role: "user",
|
|
58
|
+
content: JSON.stringify(options.input, null, 2)
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
temperature: 0,
|
|
62
|
+
responseFormat: "json_object",
|
|
63
|
+
model: { id: model }
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
const output = result.output;
|
|
67
|
+
if (!output.choices.length || typeof output.choices?.[0]?.content !== "string") {
|
|
68
|
+
throw new Error("Invalid response from the model");
|
|
69
|
+
}
|
|
70
|
+
const json = output.choices[0].content.trim();
|
|
71
|
+
if (!json.length) {
|
|
72
|
+
throw new Error("No response from the model");
|
|
73
|
+
}
|
|
74
|
+
return outputSchema.parse(JSON5.parse(json));
|
|
75
|
+
}
|
package/package.json
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@botpress/vai",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"type": "module",
|
|
3
|
+
"version": "0.0.2",
|
|
5
4
|
"description": "Vitest AI (vai) – a vitest extension for testing with LLMs",
|
|
6
5
|
"exports": {
|
|
7
6
|
".": {
|
|
8
7
|
"types": "./dist/index.d.ts",
|
|
9
8
|
"import": "./dist/index.js",
|
|
10
|
-
"require": "./dist/index.
|
|
9
|
+
"require": "./dist/index.js"
|
|
11
10
|
}
|
|
12
11
|
},
|
|
13
12
|
"scripts": {
|
|
14
|
-
"build": "
|
|
13
|
+
"build": "npm run build:types && npm run build:neutral",
|
|
14
|
+
"build:neutral": "esbuild src/**/*.ts src/*.ts --platform=neutral --outdir=dist",
|
|
15
|
+
"build:types": "tsup",
|
|
15
16
|
"watch": "tsup --watch",
|
|
16
17
|
"test": "vitest run --config vitest.config.ts",
|
|
17
18
|
"test:update": "vitest -u run --config vitest.config.ts",
|
|
@@ -30,15 +31,16 @@
|
|
|
30
31
|
"devDependencies": {
|
|
31
32
|
"@types/lodash": "^4.17.0",
|
|
32
33
|
"dotenv": "^16.3.1",
|
|
34
|
+
"esbuild": "^0.24.2",
|
|
33
35
|
"ts-node": "^10.9.2",
|
|
34
36
|
"tsup": "^8.3.5",
|
|
35
37
|
"typescript": "^5.7.2"
|
|
36
38
|
},
|
|
37
39
|
"peerDependencies": {
|
|
40
|
+
"@botpress/client": "^0.40.0",
|
|
41
|
+
"@botpress/wasm": "^1.0.1",
|
|
42
|
+
"@bpinternal/zui": "^0.13.4",
|
|
38
43
|
"lodash": "^4.17.21",
|
|
39
|
-
"@botpress/client": "^0.36.2",
|
|
40
|
-
"@botpress/sdk": "^1.6.1",
|
|
41
|
-
"@botpress/wasm": "^1.0.0",
|
|
42
44
|
"vitest": "^2 || ^3 || ^4 || ^5"
|
|
43
45
|
}
|
|
44
46
|
}
|