@botpress/zai 1.0.0-beta.2 → 1.0.0-beta.3
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/package.json +9 -2
- package/dist/src/operations/check.test.js +0 -129
- package/dist/src/operations/extract.test.js +0 -163
- package/dist/src/operations/filter.test.js +0 -151
- package/dist/src/operations/label.test.js +0 -213
- package/dist/src/operations/rewrite.test.js +0 -96
- package/dist/src/operations/summarize.test.js +0 -22
- package/dist/src/operations/text.test.js +0 -51
- package/dist/src/operations/zai-learn.test.js +0 -71
- package/dist/src/operations/zai-retry.test.js +0 -50
- package/src/adapters/adapter.ts +0 -35
- package/src/adapters/botpress-table.ts +0 -213
- package/src/adapters/memory.ts +0 -13
- package/src/env.ts +0 -54
- package/src/index.ts +0 -11
- package/src/models.ts +0 -347
- package/src/operations/__tests/botpress_docs.txt +0 -26040
- package/src/operations/__tests/index.ts +0 -30
- package/src/operations/check.test.ts +0 -155
- package/src/operations/check.ts +0 -187
- package/src/operations/constants.ts +0 -2
- package/src/operations/errors.ts +0 -9
- package/src/operations/extract.test.ts +0 -209
- package/src/operations/extract.ts +0 -291
- package/src/operations/filter.test.ts +0 -182
- package/src/operations/filter.ts +0 -231
- package/src/operations/label.test.ts +0 -239
- package/src/operations/label.ts +0 -332
- package/src/operations/rewrite.test.ts +0 -114
- package/src/operations/rewrite.ts +0 -148
- package/src/operations/summarize.test.ts +0 -25
- package/src/operations/summarize.ts +0 -193
- package/src/operations/text.test.ts +0 -60
- package/src/operations/text.ts +0 -63
- package/src/operations/zai-learn.test.ts +0 -85
- package/src/operations/zai-retry.test.ts +0 -64
- package/src/scripts/update-models.ts +0 -74
- package/src/utils.ts +0 -61
- package/src/zai.ts +0 -185
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach, afterAll } from 'vitest';
|
|
2
|
-
import { check } from '@botpress/vai';
|
|
3
|
-
import { getClient, getZai, metadata, tokenizer } from './__tests';
|
|
4
|
-
import { TableAdapter } from '../adapters/botpress-table';
|
|
5
|
-
const Zoe = `
|
|
6
|
-
Part 1. Zoe walks to the park.
|
|
7
|
-
Part 2. She meets her friend.
|
|
8
|
-
Part 3. They play together.
|
|
9
|
-
Part 4. They have a picnic.
|
|
10
|
-
Part 5. They go home.
|
|
11
|
-
`.trim();
|
|
12
|
-
describe('zai.rewrite', { timeout: 60_000 }, () => {
|
|
13
|
-
const zai = getZai();
|
|
14
|
-
it('transforms text to all caps', async () => {
|
|
15
|
-
const result = await zai.rewrite(`Hello, what is the time today?`, 'write in all caps');
|
|
16
|
-
expect(result).toBe(`HELLO, WHAT IS THE TIME TODAY?`);
|
|
17
|
-
});
|
|
18
|
-
it('transforms text to all caps and respects tokens restrictions', async () => {
|
|
19
|
-
const result = await zai.rewrite(Zoe, 'write in all caps', { length: 15 });
|
|
20
|
-
expect(tokenizer.count(result)).toBeLessThanOrEqual(20);
|
|
21
|
-
expect(result).toContain(`PART 1. ZOE WALKS TO THE PARK`);
|
|
22
|
-
expect(result).not.toContain(`PART 3`);
|
|
23
|
-
});
|
|
24
|
-
it('french translation of the story', async () => {
|
|
25
|
-
const result = await zai.rewrite(Zoe, 'translate to french');
|
|
26
|
-
check(result, 'is a french story about Zeo and with 5 parts').toBe(true);
|
|
27
|
-
});
|
|
28
|
-
it('Throws if input is bigger than the model max tokens', async () => {
|
|
29
|
-
await expect(zai.rewrite(Zoe.repeat(100_000), 'translate to french')).rejects.toThrow(/tokens/i);
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
describe('zai.learn.rewrite', { timeout: 60_000 }, () => {
|
|
33
|
-
const client = getClient();
|
|
34
|
-
let tableName = 'ZaiTestRewriteInternalTable';
|
|
35
|
-
let taskId = 'rewrite';
|
|
36
|
-
let zai = getZai();
|
|
37
|
-
beforeEach(async () => {
|
|
38
|
-
zai = getZai().with({
|
|
39
|
-
activeLearning: {
|
|
40
|
-
enable: true,
|
|
41
|
-
taskId,
|
|
42
|
-
tableName
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
afterEach(async () => {
|
|
47
|
-
try {
|
|
48
|
-
await client.deleteTableRows({ table: tableName, deleteAllRows: true });
|
|
49
|
-
}
|
|
50
|
-
catch (err) { }
|
|
51
|
-
});
|
|
52
|
-
afterAll(async () => {
|
|
53
|
-
try {
|
|
54
|
-
await client.deleteTable({ table: tableName });
|
|
55
|
-
}
|
|
56
|
-
catch (err) { }
|
|
57
|
-
});
|
|
58
|
-
it('learns rewrite rules from examples', async () => {
|
|
59
|
-
const adapter = new TableAdapter({
|
|
60
|
-
client,
|
|
61
|
-
tableName
|
|
62
|
-
});
|
|
63
|
-
const value = await zai.learn(taskId).rewrite(`Botpress is awesome`, 'write it like we want it');
|
|
64
|
-
check(value, `The text means more or less the same as "Botpress is awesome" but slightly different`).toBe(true);
|
|
65
|
-
let rows = await client.findTableRows({ table: tableName });
|
|
66
|
-
expect(rows.rows.length).toBe(1);
|
|
67
|
-
expect(rows.rows[0].output.value).toBe(value);
|
|
68
|
-
await adapter.saveExample({
|
|
69
|
-
key: 't1',
|
|
70
|
-
taskId: `zai/${taskId}`,
|
|
71
|
-
taskType: 'zai.rewrite',
|
|
72
|
-
instructions: 'write it like we want it',
|
|
73
|
-
input: 'Microsoft is a big company',
|
|
74
|
-
output: `# MICROSOFT IS A BIG COMPANY`,
|
|
75
|
-
metadata,
|
|
76
|
-
status: 'approved'
|
|
77
|
-
});
|
|
78
|
-
await adapter.saveExample({
|
|
79
|
-
key: 't2',
|
|
80
|
-
taskId: `zai/${taskId}`,
|
|
81
|
-
taskType: 'zai.rewrite',
|
|
82
|
-
instructions: 'write it like we want it',
|
|
83
|
-
input: 'Google is an evil company',
|
|
84
|
-
output: `# GOOGLE IS AN EVIL COMPANY`,
|
|
85
|
-
metadata,
|
|
86
|
-
status: 'approved'
|
|
87
|
-
});
|
|
88
|
-
const second = await zai.learn(taskId).rewrite(`Botpress is awesome`, 'write it like we want it');
|
|
89
|
-
rows = await client.findTableRows({ table: tableName });
|
|
90
|
-
expect(rows.rows.length).toBe(3);
|
|
91
|
-
check(second, `The text is "BOTPRESS IS AWESOME" and starts with a hashtag`).toBe(true);
|
|
92
|
-
expect(rows.rows.length).toBe(3);
|
|
93
|
-
expect(rows.rows[0].output.value).toBe(second);
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
//# sourceMappingURL=rewrite.test.js.map
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { check } from '@botpress/vai';
|
|
2
|
-
import { describe, it } from 'vitest';
|
|
3
|
-
import { BotpressDocumentation, getZai } from './__tests';
|
|
4
|
-
describe('zai.summarize', () => {
|
|
5
|
-
const zai = getZai();
|
|
6
|
-
it.skip('summarize long document to a concise 2000 token summary', async () => {
|
|
7
|
-
const result = await zai.summarize(BotpressDocumentation, {
|
|
8
|
-
length: 2000,
|
|
9
|
-
prompt: `Extract the Table of Contents for the Botpress Documentation. Pay special attention to all the different features. Focus on horizontal coverage of features rather than going in depth into one feature. The goal is to have a complete overview of what the documentation covers.`
|
|
10
|
-
});
|
|
11
|
-
check(result, 'The text is a summary of the Botpress documentation').toBe(true);
|
|
12
|
-
check(result, 'The text explains shortly what botpress is').toBe(true);
|
|
13
|
-
check(result, 'The text uses markdown format').toBe(true);
|
|
14
|
-
check(result, 'The text has some information about integrations').toBe(true);
|
|
15
|
-
check(result, 'The text has a section about Flows (or Workflows)').toBe(true);
|
|
16
|
-
check(result, 'The text has a section about the Botpress API').toBe(true);
|
|
17
|
-
check(result, 'The text mentions the notion of workspaces').toBe(true);
|
|
18
|
-
check(result, 'The text has some information about the Webchat').toBe(true);
|
|
19
|
-
check(result, 'The text has some information about HITL (human in the loop)').toBe(true);
|
|
20
|
-
});
|
|
21
|
-
});
|
|
22
|
-
//# sourceMappingURL=summarize.test.js.map
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { check } from '@botpress/vai';
|
|
3
|
-
import { getZai, tokenizer } from './__tests';
|
|
4
|
-
describe('zai.text', { timeout: 60_000 }, () => {
|
|
5
|
-
const zai = getZai();
|
|
6
|
-
it('generate a horror novel with no params', async () => {
|
|
7
|
-
const story = await zai.text('write a short horror novel');
|
|
8
|
-
check(story, 'is a short horror story').toBe(true);
|
|
9
|
-
});
|
|
10
|
-
it('No fluffy text at the beginning', async () => {
|
|
11
|
-
const story = await zai.text('write a short horror novel');
|
|
12
|
-
check(story, 'There is no LLM fluff at the beginning', {
|
|
13
|
-
examples: [
|
|
14
|
-
{
|
|
15
|
-
value: 'Title: A horror story\nChapter 1: The woods\nOnce upen a time, ...',
|
|
16
|
-
expected: true,
|
|
17
|
-
reason: 'It begins straight with a story, no fluff at the beginning'
|
|
18
|
-
},
|
|
19
|
-
{ value: 'Once upon a time, a ...', expected: true, reason: 'The story starts directly' },
|
|
20
|
-
{
|
|
21
|
-
value: 'Sure, I will generate a story.\nOnce upen a time, a...',
|
|
22
|
-
expected: false,
|
|
23
|
-
reason: 'There is some fluff at the beginning'
|
|
24
|
-
}
|
|
25
|
-
]
|
|
26
|
-
}).toBe(true);
|
|
27
|
-
});
|
|
28
|
-
it('No fluffy text at the end', async () => {
|
|
29
|
-
const story = await zai.text('write a short horror novel');
|
|
30
|
-
check(story, 'There is no LLM fluff at the end', {
|
|
31
|
-
examples: [
|
|
32
|
-
{
|
|
33
|
-
value: 'Title: A horror story\nChapter 1: The woods\nOnce upen a time, ... The End.',
|
|
34
|
-
expected: true,
|
|
35
|
-
reason: 'The end is clear and direct, no fluff at the end'
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
value: 'Sure, I will generate a story.\nOnce upen a time, a... The End.\nLet me know if you want more or if you are happy with this.',
|
|
39
|
-
expected: false,
|
|
40
|
-
reason: 'There is some fluff from the assistant at the end.'
|
|
41
|
-
}
|
|
42
|
-
]
|
|
43
|
-
}).toBe(true);
|
|
44
|
-
});
|
|
45
|
-
it('length/max tokens param', async () => {
|
|
46
|
-
const story = await zai.text('write a short but complete horror story (with conclusion)', { length: 100 });
|
|
47
|
-
expect(tokenizer.count(story)).toBeLessThanOrEqual(110);
|
|
48
|
-
check(story, 'could be the beginning of a horror story').toBe(true);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
//# sourceMappingURL=text.test.js.map
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, afterAll, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
-
import { getClient, getZai } from './__tests';
|
|
3
|
-
import { check } from '@botpress/vai';
|
|
4
|
-
describe('zai.learn / generic', { timeout: 60_000 }, () => {
|
|
5
|
-
const client = getClient();
|
|
6
|
-
let tableName = 'ZaiTestInternalTable';
|
|
7
|
-
let taskId = 'test';
|
|
8
|
-
let zai = getZai();
|
|
9
|
-
beforeEach(async () => {
|
|
10
|
-
zai = getZai().with({
|
|
11
|
-
activeLearning: {
|
|
12
|
-
enable: true,
|
|
13
|
-
taskId,
|
|
14
|
-
tableName
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
});
|
|
18
|
-
afterEach(async () => {
|
|
19
|
-
try {
|
|
20
|
-
await client.deleteTableRows({ table: tableName, deleteAllRows: true });
|
|
21
|
-
}
|
|
22
|
-
catch (err) { }
|
|
23
|
-
});
|
|
24
|
-
afterAll(async () => {
|
|
25
|
-
try {
|
|
26
|
-
await client.deleteTable({ table: tableName });
|
|
27
|
-
}
|
|
28
|
-
catch (err) { }
|
|
29
|
-
});
|
|
30
|
-
it('saves examples to tables', async () => {
|
|
31
|
-
const value = await zai
|
|
32
|
-
.learn(taskId)
|
|
33
|
-
.check('This text is very clearly written in English.', 'is an english sentence');
|
|
34
|
-
const { rows } = await client.findTableRows({ table: tableName });
|
|
35
|
-
expect(value).toBe(true);
|
|
36
|
-
expect(rows.length).toBe(1);
|
|
37
|
-
check(rows[0].explanation, 'is an explanation sentence');
|
|
38
|
-
expect(rows[0].explanation).not.toContain('Final Answer:');
|
|
39
|
-
expect(rows[0].output).toMatchObject({ value: true });
|
|
40
|
-
expect(rows[0].input).toMatchInlineSnapshot(`
|
|
41
|
-
{
|
|
42
|
-
"value": "This text is very clearly written in English.",
|
|
43
|
-
}
|
|
44
|
-
`);
|
|
45
|
-
expect(rows[0].taskId).toEqual('zai/test');
|
|
46
|
-
expect(rows[0].taskType).toBe('zai.check');
|
|
47
|
-
});
|
|
48
|
-
it('works even if tables are down', async () => {
|
|
49
|
-
const upsertTableRows = vi.fn(async () => {
|
|
50
|
-
throw new Error('Table is down');
|
|
51
|
-
});
|
|
52
|
-
const findTableRows = vi.fn(async () => {
|
|
53
|
-
throw new Error('Table is down');
|
|
54
|
-
});
|
|
55
|
-
const client = {
|
|
56
|
-
...getClient(),
|
|
57
|
-
findTableRows,
|
|
58
|
-
upsertTableRows
|
|
59
|
-
};
|
|
60
|
-
const value = await zai
|
|
61
|
-
.with({ client })
|
|
62
|
-
.learn(taskId)
|
|
63
|
-
.check('This text is very clearly written in English.', 'is an english sentence');
|
|
64
|
-
const { rows } = await getClient().findTableRows({ table: tableName });
|
|
65
|
-
expect(value).toBe(true);
|
|
66
|
-
expect(rows.length).toBe(0);
|
|
67
|
-
expect(upsertTableRows).toHaveBeenCalledTimes(1);
|
|
68
|
-
expect(findTableRows).toHaveBeenCalledTimes(1);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
//# sourceMappingURL=zai-learn.test.js.map
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
-
import { getClient, getZai } from './__tests';
|
|
3
|
-
describe('zai retry', { timeout: 60_000 }, () => {
|
|
4
|
-
const client = getClient();
|
|
5
|
-
let zai = getZai().with({ retry: { maxRetries: 3 } });
|
|
6
|
-
it('retries 3 times and succeeds', async () => {
|
|
7
|
-
let retryCount = 0;
|
|
8
|
-
const throwingClient = {
|
|
9
|
-
...client,
|
|
10
|
-
callAction: vi.fn((input) => {
|
|
11
|
-
if (++retryCount < 3) {
|
|
12
|
-
throw new Error('Failed to call model');
|
|
13
|
-
}
|
|
14
|
-
return client.callAction(input);
|
|
15
|
-
})
|
|
16
|
-
};
|
|
17
|
-
const value = await zai
|
|
18
|
-
.with({ client: throwingClient })
|
|
19
|
-
.check('This text is very clearly written in English.', 'is an english sentence');
|
|
20
|
-
expect(value).toBe(true);
|
|
21
|
-
expect(retryCount).toBe(3);
|
|
22
|
-
});
|
|
23
|
-
it('retries 0 times when success', async () => {
|
|
24
|
-
const fn = vi.fn((input) => client.callAction(input));
|
|
25
|
-
const throwingClient = {
|
|
26
|
-
...client,
|
|
27
|
-
callAction: fn
|
|
28
|
-
};
|
|
29
|
-
const value = await zai
|
|
30
|
-
.with({ client: throwingClient })
|
|
31
|
-
.check('This text is very clearly written in English.', 'is an english sentence');
|
|
32
|
-
expect(value).toBe(true);
|
|
33
|
-
expect(fn).toHaveBeenCalledOnce();
|
|
34
|
-
});
|
|
35
|
-
it('fails when exceeded max', async () => {
|
|
36
|
-
const fn = vi.fn(() => {
|
|
37
|
-
throw new Error('Failed to call model');
|
|
38
|
-
});
|
|
39
|
-
const throwingClient = {
|
|
40
|
-
...client,
|
|
41
|
-
callAction: fn
|
|
42
|
-
};
|
|
43
|
-
const value = zai
|
|
44
|
-
.with({ client: throwingClient, retry: { maxRetries: 1 } })
|
|
45
|
-
.check('This text is very clearly written in English.', 'is an english sentence');
|
|
46
|
-
await expect(value).rejects.toThrowError(/retries/);
|
|
47
|
-
expect(fn).toHaveBeenCalledTimes(2);
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
//# sourceMappingURL=zai-retry.test.js.map
|
package/src/adapters/adapter.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { GenerationMetadata } from '../utils'
|
|
2
|
-
|
|
3
|
-
export type SaveExampleProps<TInput, TOutput> = {
|
|
4
|
-
key: string
|
|
5
|
-
taskType: string
|
|
6
|
-
taskId: string
|
|
7
|
-
instructions: string
|
|
8
|
-
input: TInput
|
|
9
|
-
output: TOutput
|
|
10
|
-
explanation?: string
|
|
11
|
-
metadata: GenerationMetadata
|
|
12
|
-
status?: 'pending' | 'approved'
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export type GetExamplesProps<TInput> = {
|
|
16
|
-
taskType: string
|
|
17
|
-
taskId: string
|
|
18
|
-
input: TInput
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export abstract class Adapter {
|
|
22
|
-
abstract getExamples<TInput, TOutput>(
|
|
23
|
-
props: GetExamplesProps<TInput>
|
|
24
|
-
): Promise<
|
|
25
|
-
Array<{
|
|
26
|
-
key: string
|
|
27
|
-
input: TInput
|
|
28
|
-
output: TOutput
|
|
29
|
-
explanation?: string
|
|
30
|
-
similarity: number
|
|
31
|
-
}>
|
|
32
|
-
>
|
|
33
|
-
|
|
34
|
-
abstract saveExample<TInput, TOutput>(props: SaveExampleProps<TInput, TOutput>): Promise<void>
|
|
35
|
-
}
|
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
import { type Client } from '@botpress/client'
|
|
2
|
-
import { z } from '@bpinternal/zui'
|
|
3
|
-
|
|
4
|
-
import { BotpressClient, GenerationMetadata } from '../utils'
|
|
5
|
-
import { Adapter, GetExamplesProps, SaveExampleProps } from './adapter'
|
|
6
|
-
|
|
7
|
-
const CRITICAL_TAGS = {
|
|
8
|
-
system: 'true',
|
|
9
|
-
'schema-purpose': 'active-learning',
|
|
10
|
-
'schema-version': 'Oct-2024'
|
|
11
|
-
} as const
|
|
12
|
-
|
|
13
|
-
const OPTIONAL_TAGS = {
|
|
14
|
-
'x-studio-title': 'Active Learning',
|
|
15
|
-
'x-studio-description': 'Table for storing active learning tasks and examples',
|
|
16
|
-
'x-studio-readonly': 'true',
|
|
17
|
-
'x-studio-icon': 'lucide://atom',
|
|
18
|
-
'x-studio-color': 'green'
|
|
19
|
-
} as const
|
|
20
|
-
|
|
21
|
-
const FACTOR = 30
|
|
22
|
-
|
|
23
|
-
const Props = z.object({
|
|
24
|
-
client: BotpressClient,
|
|
25
|
-
tableName: z
|
|
26
|
-
.string()
|
|
27
|
-
.regex(
|
|
28
|
-
/^[a-zA-Z0-9_]{1,45}Table$/,
|
|
29
|
-
'Table name must be lowercase and contain only letters, numbers and underscores'
|
|
30
|
-
)
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
export type TableSchema = z.input<typeof TableSchema>
|
|
34
|
-
const TableSchema = z.object({
|
|
35
|
-
taskType: z.string().describe('The type of the task (filter, extract, etc.)'),
|
|
36
|
-
taskId: z.string(),
|
|
37
|
-
key: z.string().describe('A unique key for the task (e.g. a hash of the input, taskId, taskType and instructions)'),
|
|
38
|
-
instructions: z.string(),
|
|
39
|
-
input: z.object({}).passthrough().describe('The input to the task'),
|
|
40
|
-
output: z.object({}).passthrough().describe('The expected output'),
|
|
41
|
-
explanation: z.string().nullable(),
|
|
42
|
-
metadata: GenerationMetadata,
|
|
43
|
-
status: z.enum(['pending', 'rejected', 'approved']),
|
|
44
|
-
feedback: z
|
|
45
|
-
.object({
|
|
46
|
-
rating: z.enum(['very-bad', 'bad', 'good', 'very-good']),
|
|
47
|
-
comment: z.string().nullable()
|
|
48
|
-
})
|
|
49
|
-
.nullable()
|
|
50
|
-
.default(null)
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
const searchableColumns = ['input'] as const satisfies Array<keyof typeof TableSchema.shape> as string[]
|
|
54
|
-
|
|
55
|
-
const TableJsonSchema = Object.entries(TableSchema.shape).reduce((acc, [key, value]) => {
|
|
56
|
-
acc[key] = value.toJsonSchema()
|
|
57
|
-
acc[key]['x-zui'] ??= {}
|
|
58
|
-
acc[key]['x-zui'].searchable = searchableColumns.includes(key)
|
|
59
|
-
return acc
|
|
60
|
-
}, {})
|
|
61
|
-
|
|
62
|
-
export class TableAdapter extends Adapter {
|
|
63
|
-
private client: Client
|
|
64
|
-
private tableName: string
|
|
65
|
-
|
|
66
|
-
private status: 'initialized' | 'ready' | 'error'
|
|
67
|
-
private errors = [] as string[]
|
|
68
|
-
|
|
69
|
-
constructor(props: z.input<typeof Props>) {
|
|
70
|
-
super()
|
|
71
|
-
props = Props.parse(props)
|
|
72
|
-
this.client = props.client
|
|
73
|
-
this.tableName = props.tableName
|
|
74
|
-
this.status = 'ready'
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
public async getExamples<TInput, TOutput>({ taskType, taskId, input }: GetExamplesProps<TInput>) {
|
|
78
|
-
await this.assertTableExists()
|
|
79
|
-
|
|
80
|
-
const { rows } = await this.client
|
|
81
|
-
.findTableRows({
|
|
82
|
-
table: this.tableName,
|
|
83
|
-
search: JSON.stringify({ value: input }).substring(0, 1023), // Search is limited to 1024 characters
|
|
84
|
-
limit: 10, // TODO
|
|
85
|
-
filter: {
|
|
86
|
-
// Proximity match of approved examples
|
|
87
|
-
taskType,
|
|
88
|
-
taskId,
|
|
89
|
-
status: 'approved'
|
|
90
|
-
} satisfies Partial<TableSchema>
|
|
91
|
-
})
|
|
92
|
-
.catch((err) => {
|
|
93
|
-
// TODO: handle error
|
|
94
|
-
console.error(`Error fetching examples: ${err.message}`)
|
|
95
|
-
return { rows: [] }
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
return rows.map((row) => ({
|
|
99
|
-
key: row.key,
|
|
100
|
-
input: row.input.value as TInput,
|
|
101
|
-
output: row.output.value as TOutput,
|
|
102
|
-
explanation: row.explanation,
|
|
103
|
-
similarity: row.similarity ?? 0
|
|
104
|
-
}))
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
public async saveExample<TInput, TOutput>({
|
|
108
|
-
key,
|
|
109
|
-
taskType,
|
|
110
|
-
taskId,
|
|
111
|
-
instructions,
|
|
112
|
-
input,
|
|
113
|
-
output,
|
|
114
|
-
explanation,
|
|
115
|
-
metadata,
|
|
116
|
-
status = 'pending'
|
|
117
|
-
}: SaveExampleProps<TInput, TOutput>) {
|
|
118
|
-
await this.assertTableExists()
|
|
119
|
-
|
|
120
|
-
await this.client
|
|
121
|
-
.upsertTableRows({
|
|
122
|
-
table: this.tableName,
|
|
123
|
-
keyColumn: 'key',
|
|
124
|
-
rows: [
|
|
125
|
-
{
|
|
126
|
-
key,
|
|
127
|
-
taskType,
|
|
128
|
-
taskId,
|
|
129
|
-
instructions,
|
|
130
|
-
input: { value: input },
|
|
131
|
-
output: { value: output },
|
|
132
|
-
explanation: explanation ?? null,
|
|
133
|
-
status,
|
|
134
|
-
metadata
|
|
135
|
-
} satisfies TableSchema
|
|
136
|
-
]
|
|
137
|
-
})
|
|
138
|
-
.catch(() => {
|
|
139
|
-
// TODO: handle error
|
|
140
|
-
})
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
private async assertTableExists() {
|
|
144
|
-
if (this.status !== 'ready') {
|
|
145
|
-
return
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const { table, created } = await this.client
|
|
149
|
-
.getOrCreateTable({
|
|
150
|
-
table: this.tableName,
|
|
151
|
-
factor: FACTOR,
|
|
152
|
-
frozen: true,
|
|
153
|
-
isComputeEnabled: false,
|
|
154
|
-
tags: {
|
|
155
|
-
...CRITICAL_TAGS,
|
|
156
|
-
...OPTIONAL_TAGS
|
|
157
|
-
},
|
|
158
|
-
schema: TableJsonSchema
|
|
159
|
-
})
|
|
160
|
-
.catch((err) => {
|
|
161
|
-
this.status = 'error'
|
|
162
|
-
this.errors = [err.message]
|
|
163
|
-
return { table: null, created: false }
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
if (!table) {
|
|
167
|
-
return
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (!created) {
|
|
171
|
-
const issues: string[] = []
|
|
172
|
-
|
|
173
|
-
if (table.factor !== FACTOR) {
|
|
174
|
-
issues.push(`Factor is ${table.factor} instead of ${FACTOR}`)
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if (table.frozen !== true) {
|
|
178
|
-
issues.push('Table is not frozen')
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
for (const [key, value] of Object.entries(CRITICAL_TAGS)) {
|
|
182
|
-
if (table.tags?.[key] !== value) {
|
|
183
|
-
issues.push(`Tag ${key} is ${table.tags?.[key]} instead of ${value}`)
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
for (const key of Object.keys(TableJsonSchema)) {
|
|
188
|
-
const column = table.schema?.properties[key]
|
|
189
|
-
const expected = TableJsonSchema[key] as { type: string }
|
|
190
|
-
|
|
191
|
-
if (!column) {
|
|
192
|
-
issues.push(`Column ${key} is missing`)
|
|
193
|
-
continue
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (column.type !== expected.type) {
|
|
197
|
-
issues.push(`Column ${key} has type ${column.type} instead of ${expected.type}`)
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (expected['x-zui'].searchable && !column['x-zui'].searchable) {
|
|
201
|
-
issues.push(`Column ${key} is not searchable but should be`)
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (issues.length) {
|
|
206
|
-
this.status = 'error'
|
|
207
|
-
this.errors = issues
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
this.status = 'initialized'
|
|
212
|
-
}
|
|
213
|
-
}
|
package/src/adapters/memory.ts
DELETED
package/src/env.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { z } from '@bpinternal/zui'
|
|
2
|
-
import dotenv from 'dotenv'
|
|
3
|
-
|
|
4
|
-
dotenv.config({ override: false })
|
|
5
|
-
dotenv.populate(
|
|
6
|
-
process.env,
|
|
7
|
-
{
|
|
8
|
-
VITE_CLOUD_API_ENDPOINT: 'https://api.botpress.dev'
|
|
9
|
-
},
|
|
10
|
-
{ override: false }
|
|
11
|
-
)
|
|
12
|
-
|
|
13
|
-
const envVariables = z.object({
|
|
14
|
-
CI: z.coerce.boolean().optional().describe('Indicates whether the tests are running in a CI environment'),
|
|
15
|
-
VITE_CLOUD_API_ENDPOINT: z.string(),
|
|
16
|
-
VITE_BOT_ID: z.string(),
|
|
17
|
-
VITE_CLOUD_PAT: z.string(),
|
|
18
|
-
// for CI
|
|
19
|
-
VITEST_CLOUD_PAT: z.string().optional(),
|
|
20
|
-
VITEST_BOT_ID: z.string().optional()
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
const result = envVariables.safeParse(process.env)
|
|
24
|
-
|
|
25
|
-
if (!result.success) {
|
|
26
|
-
for (const error of result.error.errors) {
|
|
27
|
-
if (error.code === 'invalid_type') {
|
|
28
|
-
console.error(`Missing environment variable: ${error.path.join('.')}`)
|
|
29
|
-
} else {
|
|
30
|
-
console.error(error)
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
type Deprecated = Omit<
|
|
36
|
-
{
|
|
37
|
-
[key: string]: any
|
|
38
|
-
},
|
|
39
|
-
keyof z.infer<typeof envVariables>
|
|
40
|
-
>
|
|
41
|
-
|
|
42
|
-
type AllEnv = z.infer<typeof envVariables> & Deprecated
|
|
43
|
-
|
|
44
|
-
/** @internal */
|
|
45
|
-
declare global {
|
|
46
|
-
namespace NodeJS {
|
|
47
|
-
interface ProcessEnv extends AllEnv {
|
|
48
|
-
/** @deprecated please define your ENV variable in {@link env.ts} */
|
|
49
|
-
[key: keyof Deprecated]: any
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export {}
|
package/src/index.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { Zai } from './zai'
|
|
2
|
-
|
|
3
|
-
import './operations/text'
|
|
4
|
-
import './operations/rewrite'
|
|
5
|
-
import './operations/summarize'
|
|
6
|
-
import './operations/check'
|
|
7
|
-
import './operations/filter'
|
|
8
|
-
import './operations/extract'
|
|
9
|
-
import './operations/label'
|
|
10
|
-
|
|
11
|
-
export { Zai }
|