@botpress/vai 0.0.1-beta.7 → 0.0.2-beta.1
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 +11 -9
- 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
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
import { z } from "@bpinternal/zui";
|
|
3
|
+
import { Context } from "../context";
|
|
4
|
+
import { asyncExpect } from "../utils/asyncAssertion";
|
|
5
|
+
import { predictJson } from "../utils/predictJson";
|
|
6
|
+
import { makeToMatchInlineSnapshot, toAssertion } from "./extension";
|
|
7
|
+
export function check(value, condition, options) {
|
|
8
|
+
const promise = predictJson({
|
|
9
|
+
systemMessage: `Check that the value meets the condition: ${condition}`,
|
|
10
|
+
examples: options?.examples?.map(({ value: value2, reason, expected }) => ({
|
|
11
|
+
input: value2,
|
|
12
|
+
output: { reason, result: expected }
|
|
13
|
+
})),
|
|
14
|
+
outputSchema: z.boolean(),
|
|
15
|
+
model: Context.evaluatorModel,
|
|
16
|
+
input: value
|
|
17
|
+
});
|
|
18
|
+
return {
|
|
19
|
+
...toAssertion(promise),
|
|
20
|
+
toBe: (expected) => asyncExpect(promise, (expect) => expect.toEqual(expected)),
|
|
21
|
+
toMatchInlineSnapshot: makeToMatchInlineSnapshot(promise)
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
import json5 from "json5";
|
|
3
|
+
import { expect } from "vitest";
|
|
4
|
+
import { getCurrentTest } from "vitest/suite";
|
|
5
|
+
import { asyncExpect } from "../utils/asyncAssertion";
|
|
6
|
+
export const toAssertion = (promise) => {
|
|
7
|
+
return {
|
|
8
|
+
then: promise.then.bind(promise),
|
|
9
|
+
value: promise.then((value) => value.result)
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
export const makeToMatchInlineSnapshot = (promise) => async (expected) => {
|
|
13
|
+
const stack = new Error().stack.split("\n")[2];
|
|
14
|
+
const newStack = `
|
|
15
|
+
at __INLINE_SNAPSHOT__ (node:internal/process/task_queues:1:1)
|
|
16
|
+
at randomLine (node:internal/process/task_queues:1:1)
|
|
17
|
+
${stack}
|
|
18
|
+
`.trim();
|
|
19
|
+
const obj = json5.parse(expected ?? '""');
|
|
20
|
+
const expectation = asyncExpect(promise, (expect2) => expect2.toMatchObject(obj)).catch(() => {
|
|
21
|
+
});
|
|
22
|
+
try {
|
|
23
|
+
expect((await promise).result).toMatchObject(obj);
|
|
24
|
+
} catch (err) {
|
|
25
|
+
const newError = new Error();
|
|
26
|
+
newError.stack = newStack;
|
|
27
|
+
expect.getState().snapshotState.match({
|
|
28
|
+
isInline: true,
|
|
29
|
+
received: (await promise).result,
|
|
30
|
+
testName: getCurrentTest().name,
|
|
31
|
+
error: newError,
|
|
32
|
+
inlineSnapshot: expected
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return expectation;
|
|
36
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
import { Context } from "../context";
|
|
3
|
+
import { asyncExpect } from "../utils/asyncAssertion";
|
|
4
|
+
import { predictJson } from "../utils/predictJson";
|
|
5
|
+
import { makeToMatchInlineSnapshot, toAssertion } from "./extension";
|
|
6
|
+
export function extract(value, shape, options) {
|
|
7
|
+
const additionalMessage = options?.description ? `
|
|
8
|
+
In order to extract the right information, follow these instructions:
|
|
9
|
+
${options.description}
|
|
10
|
+
` : "";
|
|
11
|
+
const promise = predictJson({
|
|
12
|
+
systemMessage: "From the given input, extract the required information into the requested format." + additionalMessage.trim(),
|
|
13
|
+
examples: options?.examples?.map(({ value: value2, reason, extracted }) => ({
|
|
14
|
+
input: value2,
|
|
15
|
+
output: { reason, result: extracted }
|
|
16
|
+
})),
|
|
17
|
+
outputSchema: shape,
|
|
18
|
+
model: Context.evaluatorModel,
|
|
19
|
+
input: value
|
|
20
|
+
});
|
|
21
|
+
return {
|
|
22
|
+
...toAssertion(promise),
|
|
23
|
+
toBe: (expected) => asyncExpect(promise, (expect) => expect.toEqual(expected)),
|
|
24
|
+
toMatchObject: (expected) => asyncExpect(promise, (expect) => expect.toMatchObject(expected)),
|
|
25
|
+
toMatchInlineSnapshot: makeToMatchInlineSnapshot(promise)
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
import { z } from "@bpinternal/zui";
|
|
3
|
+
import { Context } from "../context";
|
|
4
|
+
import { asyncExpect } from "../utils/asyncAssertion";
|
|
5
|
+
import { predictJson } from "../utils/predictJson";
|
|
6
|
+
import { makeToMatchInlineSnapshot, toAssertion } from "./extension";
|
|
7
|
+
export function filter(values, condition, options) {
|
|
8
|
+
const mappedValues = values.map(
|
|
9
|
+
(_, idx) => z.object({
|
|
10
|
+
index: z.literal(idx),
|
|
11
|
+
reason: z.string(),
|
|
12
|
+
keep: z.boolean()
|
|
13
|
+
})
|
|
14
|
+
);
|
|
15
|
+
const input = values.map((value, idx) => ({
|
|
16
|
+
index: idx,
|
|
17
|
+
value
|
|
18
|
+
}));
|
|
19
|
+
const schema = z.tuple(mappedValues).describe(
|
|
20
|
+
"An array of the objects with the index and a boolean value indicating if the object should be kept or not"
|
|
21
|
+
);
|
|
22
|
+
const promise = predictJson({
|
|
23
|
+
systemMessage: `
|
|
24
|
+
Based on the following qualification criteria, you need to filter the given list of objects.
|
|
25
|
+
Citeria: ${condition}
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
You need to return an array of objects with the index and a boolean value indicating if the object should be kept or not.
|
|
29
|
+
`.trim(),
|
|
30
|
+
examples: options?.examples ? [
|
|
31
|
+
{
|
|
32
|
+
input: options?.examples?.map((v, index) => ({
|
|
33
|
+
index,
|
|
34
|
+
value: v.value
|
|
35
|
+
})),
|
|
36
|
+
output: {
|
|
37
|
+
reason: "Here are some examples",
|
|
38
|
+
result: options?.examples?.map((v, idx) => ({
|
|
39
|
+
index: idx,
|
|
40
|
+
reason: v.reason,
|
|
41
|
+
keep: v.keep
|
|
42
|
+
}))
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
] : void 0,
|
|
46
|
+
outputSchema: schema,
|
|
47
|
+
model: Context.evaluatorModel,
|
|
48
|
+
input
|
|
49
|
+
}).then((x) => {
|
|
50
|
+
const results = schema.parse(x.result);
|
|
51
|
+
return {
|
|
52
|
+
result: values.filter((_, idx) => results.find((r) => r.index === idx)?.keep),
|
|
53
|
+
reason: x.reason
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
...toAssertion(promise),
|
|
58
|
+
toBe: (expected) => asyncExpect(promise, (expect) => expect.toEqual(expected)),
|
|
59
|
+
toMatchInlineSnapshot: makeToMatchInlineSnapshot(promise),
|
|
60
|
+
toHaveNoneFiltered: () => asyncExpect(promise, (expect) => expect.toEqual(values)),
|
|
61
|
+
toHaveSomeFiltered: () => asyncExpect(promise, (expect) => expect.not.toEqual(values)),
|
|
62
|
+
toBeEmpty: () => asyncExpect(promise, (expect) => expect.toHaveLength(0)),
|
|
63
|
+
length: {
|
|
64
|
+
toBe: (expected) => asyncExpect(promise, (expect) => expect.toHaveLength(expected)),
|
|
65
|
+
toBeGreaterThanOrEqual: (expected) => asyncExpect(promise, (expect) => expect.length.greaterThanOrEqual(expected)),
|
|
66
|
+
toBeLessThanOrEqual: (expected) => asyncExpect(promise, (expect) => expect.length.lessThanOrEqual(expected)),
|
|
67
|
+
toBeBetween: (min, max) => asyncExpect(promise, (expect) => expect.length.within(min, max))
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
import { z } from "@bpinternal/zui";
|
|
3
|
+
import { Context } from "../context";
|
|
4
|
+
import { asyncExpect } from "../utils/asyncAssertion";
|
|
5
|
+
import { predictJson } from "../utils/predictJson";
|
|
6
|
+
import { makeToMatchInlineSnapshot, toAssertion } from "./extension";
|
|
7
|
+
export function rate(value, condition, options) {
|
|
8
|
+
const schema = z.number().min(1).max(5).describe("Rating score, higher is better (1 is the worst, 5 is the best)");
|
|
9
|
+
const promise = predictJson({
|
|
10
|
+
systemMessage: `Based on the following qualification criteria, you need to rate the given situation from a score of 1 to 5.
|
|
11
|
+
Scoring: 1 is the worst score, 5 is the best score possible.
|
|
12
|
+
Criteria: ${condition}`,
|
|
13
|
+
examples: options?.examples?.map(({ value: value2, reason, rating }) => ({
|
|
14
|
+
input: value2,
|
|
15
|
+
output: { reason, result: rating }
|
|
16
|
+
})),
|
|
17
|
+
outputSchema: schema,
|
|
18
|
+
model: Context.evaluatorModel,
|
|
19
|
+
input: value
|
|
20
|
+
}).then((x) => {
|
|
21
|
+
return {
|
|
22
|
+
result: typeof x.result === "number" ? x.result : parseInt(x.result, 10),
|
|
23
|
+
reason: x.reason
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
return {
|
|
27
|
+
...toAssertion(promise),
|
|
28
|
+
toBe: (expected) => asyncExpect(promise, (expect) => expect.toEqual(expected)),
|
|
29
|
+
toMatchInlineSnapshot: makeToMatchInlineSnapshot(promise),
|
|
30
|
+
toBeGreaterThanOrEqual: (expected) => asyncExpect(promise, (expect) => expect.toBeGreaterThanOrEqual(expected)),
|
|
31
|
+
toBeLessThanOrEqual: (expected) => asyncExpect(promise, (expect) => expect.toBeLessThanOrEqual(expected))
|
|
32
|
+
};
|
|
33
|
+
}
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
import { onTestFinished } from "vitest";
|
|
3
|
+
import { getCurrentTest } from "vitest/suite";
|
|
4
|
+
const getTestMetadata = () => {
|
|
5
|
+
const test = getCurrentTest();
|
|
6
|
+
return test?.meta ?? {
|
|
7
|
+
isVaiTest: false
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
class VaiContext {
|
|
11
|
+
#client = null;
|
|
12
|
+
#wrapError = false;
|
|
13
|
+
get wrapError() {
|
|
14
|
+
return this.#wrapError;
|
|
15
|
+
}
|
|
16
|
+
get client() {
|
|
17
|
+
if (!this.#client) {
|
|
18
|
+
throw new Error("Botpress client is not set");
|
|
19
|
+
}
|
|
20
|
+
return this.#client;
|
|
21
|
+
}
|
|
22
|
+
get evaluatorModel() {
|
|
23
|
+
return getTestMetadata().evaluatorModel ?? "openai__gpt-4o-mini-2024-07-18";
|
|
24
|
+
}
|
|
25
|
+
get scenario() {
|
|
26
|
+
return getTestMetadata().scenario;
|
|
27
|
+
}
|
|
28
|
+
get isVaiTest() {
|
|
29
|
+
return getTestMetadata().isVaiTest;
|
|
30
|
+
}
|
|
31
|
+
setClient(cognitive) {
|
|
32
|
+
this.#client = cognitive;
|
|
33
|
+
}
|
|
34
|
+
swallowErrors() {
|
|
35
|
+
if (!getCurrentTest()) {
|
|
36
|
+
throw new Error("cancelBail is a Vitest hook and must be called within a test");
|
|
37
|
+
}
|
|
38
|
+
this.#wrapError = true;
|
|
39
|
+
onTestFinished(() => {
|
|
40
|
+
this.#wrapError = false;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export const Context = new VaiContext();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
import { getCurrentTest } from "vitest/suite";
|
|
3
|
+
export const setEvaluator = (model) => {
|
|
4
|
+
const test = getCurrentTest();
|
|
5
|
+
if (!test) {
|
|
6
|
+
throw new Error("setEvaluator is a Vitest hook and must be called within a test");
|
|
7
|
+
}
|
|
8
|
+
const meta = test.meta;
|
|
9
|
+
meta.evaluatorModel = model;
|
|
10
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import { z } from '@
|
|
1
|
+
import * as _bpinternal_zui from '@bpinternal/zui';
|
|
2
|
+
import { z, AnyZodObject } from '@bpinternal/zui';
|
|
3
3
|
import { TestFunction } from 'vitest';
|
|
4
4
|
import { Client } from '@botpress/client';
|
|
5
5
|
|
|
6
6
|
type ScenarioLike = z.infer<typeof ScenarioLike>;
|
|
7
|
-
declare const ScenarioLike:
|
|
8
|
-
name:
|
|
9
|
-
}, "passthrough",
|
|
10
|
-
name:
|
|
11
|
-
},
|
|
12
|
-
name:
|
|
13
|
-
},
|
|
14
|
-
id:
|
|
15
|
-
}, "passthrough",
|
|
16
|
-
id:
|
|
17
|
-
},
|
|
18
|
-
id:
|
|
19
|
-
},
|
|
7
|
+
declare const ScenarioLike: _bpinternal_zui.ZodUnion<[_bpinternal_zui.ZodString, _bpinternal_zui.ZodObject<{
|
|
8
|
+
name: _bpinternal_zui.ZodString;
|
|
9
|
+
}, "passthrough", _bpinternal_zui.ZodTypeAny, _bpinternal_zui.objectOutputType<{
|
|
10
|
+
name: _bpinternal_zui.ZodString;
|
|
11
|
+
}, _bpinternal_zui.ZodTypeAny, "passthrough">, _bpinternal_zui.objectInputType<{
|
|
12
|
+
name: _bpinternal_zui.ZodString;
|
|
13
|
+
}, _bpinternal_zui.ZodTypeAny, "passthrough">>, _bpinternal_zui.ZodObject<{
|
|
14
|
+
id: _bpinternal_zui.ZodString;
|
|
15
|
+
}, "passthrough", _bpinternal_zui.ZodTypeAny, _bpinternal_zui.objectOutputType<{
|
|
16
|
+
id: _bpinternal_zui.ZodString;
|
|
17
|
+
}, _bpinternal_zui.ZodTypeAny, "passthrough">, _bpinternal_zui.objectInputType<{
|
|
18
|
+
id: _bpinternal_zui.ZodString;
|
|
19
|
+
}, _bpinternal_zui.ZodTypeAny, "passthrough">>]>;
|
|
20
20
|
declare function compare<T extends ReadonlyArray<ScenarioLike>>(name: string | Function, scenarios: T, fn?: TestFunction<{
|
|
21
21
|
scenario: T[number];
|
|
22
22
|
}>): void;
|
|
23
23
|
|
|
24
24
|
type Input = z.infer<typeof Input>;
|
|
25
|
-
declare const Input:
|
|
25
|
+
declare const Input: _bpinternal_zui.ZodUnion<[_bpinternal_zui.ZodUnion<[_bpinternal_zui.ZodString, z.ZodTransformer<_bpinternal_zui.ZodObject<{}, "passthrough", _bpinternal_zui.ZodTypeAny, _bpinternal_zui.objectOutputType<{}, _bpinternal_zui.ZodTypeAny, "passthrough">, _bpinternal_zui.objectInputType<{}, _bpinternal_zui.ZodTypeAny, "passthrough">>, _bpinternal_zui.objectOutputType<{}, _bpinternal_zui.ZodTypeAny, "passthrough">, _bpinternal_zui.objectInputType<{}, _bpinternal_zui.ZodTypeAny, "passthrough">>]>, _bpinternal_zui.ZodArray<_bpinternal_zui.ZodAny, "many">]>;
|
|
26
26
|
type Output<T = any> = z.infer<typeof Output> & {
|
|
27
27
|
result: T;
|
|
28
28
|
};
|
|
29
|
-
declare const Output:
|
|
30
|
-
reason:
|
|
31
|
-
result:
|
|
32
|
-
}, "strip",
|
|
29
|
+
declare const Output: _bpinternal_zui.ZodObject<{
|
|
30
|
+
reason: _bpinternal_zui.ZodString;
|
|
31
|
+
result: _bpinternal_zui.ZodAny;
|
|
32
|
+
}, "strip", _bpinternal_zui.ZodTypeAny, {
|
|
33
33
|
reason: string;
|
|
34
34
|
result?: any;
|
|
35
35
|
}, {
|
|
@@ -64,7 +64,7 @@ type ExtractOptions<T, S> = {
|
|
|
64
64
|
reason: string;
|
|
65
65
|
}[];
|
|
66
66
|
};
|
|
67
|
-
declare function extract<T extends Input, S extends
|
|
67
|
+
declare function extract<T extends Input, S extends AnyZodObject>(value: T, shape: S, options?: ExtractOptions<T, z.infer<S>>): {
|
|
68
68
|
toBe: (expected: z.infer<S>) => Promise<Output<z.infer<S>> | AsyncExpectError<z.infer<S>>>;
|
|
69
69
|
toMatchObject: (expected: Partial<z.infer<S>>) => Promise<Output<z.infer<S>> | AsyncExpectError<z.infer<S>>>;
|
|
70
70
|
toMatchInlineSnapshot: (expected?: string) => Promise<void | Output<z.infer<S>> | AsyncExpectError<z.infer<S>>>;
|