@botpress/zai 2.0.7 → 2.0.10
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/adapters/botpress-table.js +4 -3
- package/dist/index.d.ts +73 -280
- package/dist/operations/check.js +19 -8
- package/dist/operations/filter.js +4 -4
- package/dist/operations/label.js +5 -5
- package/dist/operations/rewrite.js +2 -2
- package/dist/utils.js +0 -13
- package/dist/zai.js +8 -5
- package/e2e/client.ts +151 -0
- package/e2e/data/cache.jsonl +113 -118
- package/e2e/utils.ts +2 -54
- package/package.json +4 -3
- package/src/adapters/botpress-table.ts +25 -4
- package/src/operations/check.ts +32 -10
- package/src/operations/extract.ts +7 -1
- package/src/operations/filter.ts +17 -6
- package/src/operations/label.ts +18 -8
- package/src/operations/rewrite.ts +17 -6
- package/src/operations/summarize.ts +19 -2
- package/src/operations/text.ts +5 -1
- package/src/utils.ts +12 -19
- package/src/zai.ts +24 -8
package/e2e/client.ts
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { Client } from '@botpress/client'
|
|
2
|
+
import { Cognitive } from '@botpress/cognitive'
|
|
3
|
+
import { diffLines } from 'diff'
|
|
4
|
+
import fs from 'node:fs'
|
|
5
|
+
import path from 'node:path'
|
|
6
|
+
import { expect } from 'vitest'
|
|
7
|
+
|
|
8
|
+
function stringifyWithSortedKeys(obj: any, space?: number): string {
|
|
9
|
+
function sortKeys(input: any): any {
|
|
10
|
+
if (Array.isArray(input)) {
|
|
11
|
+
return input.map(sortKeys)
|
|
12
|
+
} else if (input && typeof input === 'object' && input.constructor === Object) {
|
|
13
|
+
return Object.keys(input)
|
|
14
|
+
.sort()
|
|
15
|
+
.reduce(
|
|
16
|
+
(acc, key) => {
|
|
17
|
+
acc[key] = sortKeys(input[key])
|
|
18
|
+
return acc
|
|
19
|
+
},
|
|
20
|
+
{} as Record<string, any>
|
|
21
|
+
)
|
|
22
|
+
} else {
|
|
23
|
+
return input
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return JSON.stringify(sortKeys(obj), null, space)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function readJSONL<T>(filePath: string, keyProperty: keyof T): Map<string, T> {
|
|
31
|
+
const lines = fs.readFileSync(filePath, 'utf-8').split(/\r?\n/).filter(Boolean)
|
|
32
|
+
|
|
33
|
+
const map = new Map<string, T>()
|
|
34
|
+
|
|
35
|
+
for (const line of lines) {
|
|
36
|
+
try {
|
|
37
|
+
const obj = JSON.parse(line) as T
|
|
38
|
+
const key = String(obj[keyProperty])
|
|
39
|
+
map.set(key, obj)
|
|
40
|
+
} catch {}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return map
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
type CacheEntry = { key: string; value: any; test: string; input: string }
|
|
47
|
+
|
|
48
|
+
const cache: Map<string, CacheEntry> = readJSONL(path.resolve(__dirname, './data/cache.jsonl'), 'key')
|
|
49
|
+
const cacheByTest: Map<string, CacheEntry> = readJSONL(path.resolve(__dirname, './data/cache.jsonl'), 'test')
|
|
50
|
+
|
|
51
|
+
class CachedClient extends Client {
|
|
52
|
+
#client: Client
|
|
53
|
+
#callsByTest: Record<string, number> = {}
|
|
54
|
+
|
|
55
|
+
public constructor(options: ConstructorParameters<typeof Client>[0]) {
|
|
56
|
+
super(options)
|
|
57
|
+
this.#client = new Client(options)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public callAction = async (...args: Parameters<Client['callAction']>) => {
|
|
61
|
+
const currentTestName = expect.getState().currentTestName ?? 'default'
|
|
62
|
+
this.#callsByTest[currentTestName] ||= 0
|
|
63
|
+
this.#callsByTest[currentTestName]++
|
|
64
|
+
|
|
65
|
+
const testKey = `${currentTestName}-${this.#callsByTest[currentTestName]}`
|
|
66
|
+
|
|
67
|
+
const key = fastHash(stringifyWithSortedKeys(args))
|
|
68
|
+
const cached = cache.get(key)
|
|
69
|
+
|
|
70
|
+
if (cached) {
|
|
71
|
+
return cached.value
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (process.env.CI && cacheByTest.has(testKey)) {
|
|
75
|
+
console.info(`Cache miss for ${key} in test ${testKey}`)
|
|
76
|
+
console.info(
|
|
77
|
+
diffLines(
|
|
78
|
+
JSON.stringify(JSON.parse(cacheByTest.get(testKey)?.input!), null, 2),
|
|
79
|
+
JSON.stringify(JSON.parse(stringifyWithSortedKeys(args)), null, 2)
|
|
80
|
+
)
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const response = await this.#client.callAction(...args)
|
|
85
|
+
cache.set(key, { key, value: response, test: testKey, input: stringifyWithSortedKeys(args) })
|
|
86
|
+
|
|
87
|
+
fs.appendFileSync(
|
|
88
|
+
path.resolve(__dirname, './data/cache.jsonl'),
|
|
89
|
+
JSON.stringify({
|
|
90
|
+
test: testKey,
|
|
91
|
+
key,
|
|
92
|
+
input: stringifyWithSortedKeys(args),
|
|
93
|
+
value: response,
|
|
94
|
+
}) + '\n'
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
return response
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public clone() {
|
|
101
|
+
return this
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export const getCachedCognitiveClient = () => {
|
|
106
|
+
const cognitive = new Cognitive({
|
|
107
|
+
client: new CachedClient({
|
|
108
|
+
apiUrl: process.env.CLOUD_API_ENDPOINT ?? 'https://api.botpress.dev',
|
|
109
|
+
botId: process.env.CLOUD_BOT_ID,
|
|
110
|
+
token: process.env.CLOUD_PAT,
|
|
111
|
+
}),
|
|
112
|
+
provider: {
|
|
113
|
+
deleteModelPreferences: async () => {},
|
|
114
|
+
saveModelPreferences: async () => {},
|
|
115
|
+
fetchInstalledModels: async () => [
|
|
116
|
+
{
|
|
117
|
+
ref: 'openai:gpt-4o-2024-11-20',
|
|
118
|
+
integration: 'openai',
|
|
119
|
+
id: 'gpt-4o-2024-11-20',
|
|
120
|
+
name: 'GPT-4o (November 2024)',
|
|
121
|
+
description:
|
|
122
|
+
"GPT-4o (“o” for “omni”) is OpenAI's most advanced model. It is multimodal (accepting text or image inputs and outputting text), and it has the same high intelligence as GPT-4 Turbo but is cheaper and more efficient.",
|
|
123
|
+
input: {
|
|
124
|
+
costPer1MTokens: 2.5,
|
|
125
|
+
maxTokens: 128000,
|
|
126
|
+
},
|
|
127
|
+
output: {
|
|
128
|
+
costPer1MTokens: 10,
|
|
129
|
+
maxTokens: 16384,
|
|
130
|
+
},
|
|
131
|
+
tags: ['recommended', 'vision', 'general-purpose', 'coding', 'agents', 'function-calling'],
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
fetchModelPreferences: async () => ({
|
|
135
|
+
best: ['openai:gpt-4o-2024-11-20'] as const,
|
|
136
|
+
fast: ['openai:gpt-4o-2024-11-20'] as const,
|
|
137
|
+
downtimes: [],
|
|
138
|
+
}),
|
|
139
|
+
},
|
|
140
|
+
})
|
|
141
|
+
return cognitive
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function fastHash(str: string): string {
|
|
145
|
+
let hash = 0
|
|
146
|
+
for (let i = 0; i < str.length; i++) {
|
|
147
|
+
hash = (hash << 5) - hash + str.charCodeAt(i)
|
|
148
|
+
hash |= 0 // Convert to 32bit integer
|
|
149
|
+
}
|
|
150
|
+
return (hash >>> 0).toString(16) // Convert to unsigned and then to hex
|
|
151
|
+
}
|