@botpress/zai 2.0.16 → 2.1.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.
- package/dist/context.js +131 -0
- package/dist/emitter.js +42 -0
- package/dist/index.d.ts +104 -9
- package/dist/operations/check.js +46 -27
- package/dist/operations/extract.js +63 -46
- package/dist/operations/filter.js +34 -19
- package/dist/operations/label.js +65 -42
- package/dist/operations/rewrite.js +37 -17
- package/dist/operations/summarize.js +32 -13
- package/dist/operations/text.js +28 -8
- package/dist/response.js +82 -0
- package/dist/tokenizer.js +11 -0
- package/e2e/client.ts +43 -29
- package/e2e/data/cache.jsonl +276 -0
- package/package.json +11 -3
- package/src/context.ts +197 -0
- package/src/emitter.ts +49 -0
- package/src/operations/check.ts +99 -49
- package/src/operations/extract.ts +85 -60
- package/src/operations/filter.ts +62 -35
- package/src/operations/label.ts +117 -62
- package/src/operations/rewrite.ts +50 -21
- package/src/operations/summarize.ts +40 -14
- package/src/operations/text.ts +32 -8
- package/src/response.ts +114 -0
- package/src/tokenizer.ts +14 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@botpress/zai",
|
|
3
3
|
"description": "Zui AI (zai) – An LLM utility library written on top of Zui and the Botpress API",
|
|
4
|
-
"version": "2.0
|
|
4
|
+
"version": "2.1.0",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"exports": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
13
|
"check:type": "tsc --noEmit",
|
|
14
|
-
"build": "bp add -y && pnpm run build:types && pnpm run build:neutral",
|
|
14
|
+
"build": "bp add -y && pnpm run build:types && pnpm run build:neutral && size-limit",
|
|
15
15
|
"build:neutral": "ts-node -T ./build.ts",
|
|
16
16
|
"build:types": "tsup",
|
|
17
17
|
"watch": "tsup --watch",
|
|
@@ -19,11 +19,17 @@
|
|
|
19
19
|
"test:e2e:update": "vitest -u run --config vitest.config.ts",
|
|
20
20
|
"test:e2e:watch": "vitest --config vitest.config.ts"
|
|
21
21
|
},
|
|
22
|
+
"size-limit": [
|
|
23
|
+
{
|
|
24
|
+
"limit": "50 kB",
|
|
25
|
+
"path": "dist/**/*.js"
|
|
26
|
+
}
|
|
27
|
+
],
|
|
22
28
|
"keywords": [],
|
|
23
29
|
"author": "",
|
|
24
30
|
"license": "ISC",
|
|
25
31
|
"dependencies": {
|
|
26
|
-
"@botpress/cognitive": "0.1.
|
|
32
|
+
"@botpress/cognitive": "0.1.29",
|
|
27
33
|
"json5": "^2.2.3",
|
|
28
34
|
"jsonrepair": "^3.10.0",
|
|
29
35
|
"lodash-es": "^4.17.21"
|
|
@@ -32,12 +38,14 @@
|
|
|
32
38
|
"@botpress/client": "workspace:^",
|
|
33
39
|
"@botpress/common": "workspace:*",
|
|
34
40
|
"@botpress/vai": "workspace:*",
|
|
41
|
+
"@size-limit/file": "^11.1.6",
|
|
35
42
|
"@types/lodash-es": "^4.17.12",
|
|
36
43
|
"diff": "^8.0.1",
|
|
37
44
|
"dotenv": "^16.4.4",
|
|
38
45
|
"esbuild": "^0.16.12",
|
|
39
46
|
"glob": "^9.3.4",
|
|
40
47
|
"lodash": "^4.17.21",
|
|
48
|
+
"size-limit": "^11.1.6",
|
|
41
49
|
"tsup": "^8.0.2"
|
|
42
50
|
},
|
|
43
51
|
"peerDependencies": {
|
package/src/context.ts
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { Cognitive, Model, GenerateContentInput, GenerateContentOutput } from '@botpress/cognitive'
|
|
2
|
+
import { Adapter } from './adapters/adapter'
|
|
3
|
+
import { EventEmitter } from './emitter'
|
|
4
|
+
|
|
5
|
+
type Meta = Awaited<ReturnType<Cognitive['generateContent']>>['meta']
|
|
6
|
+
|
|
7
|
+
type GenerateContentProps<T> = Omit<GenerateContentInput, 'model' | 'signal'> & {
|
|
8
|
+
maxRetries?: number
|
|
9
|
+
transform?: (text: string | undefined, output: GenerateContentOutput) => T
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type ZaiContextProps = {
|
|
13
|
+
client: Cognitive
|
|
14
|
+
taskType: string
|
|
15
|
+
taskId: string
|
|
16
|
+
modelId: string
|
|
17
|
+
adapter?: Adapter
|
|
18
|
+
source?: GenerateContentInput['meta']
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type Usage = {
|
|
22
|
+
requests: {
|
|
23
|
+
requests: number
|
|
24
|
+
errors: number
|
|
25
|
+
responses: number
|
|
26
|
+
cached: number
|
|
27
|
+
percentage: number
|
|
28
|
+
}
|
|
29
|
+
cost: {
|
|
30
|
+
input: number
|
|
31
|
+
output: number
|
|
32
|
+
total: number
|
|
33
|
+
}
|
|
34
|
+
tokens: {
|
|
35
|
+
input: number
|
|
36
|
+
output: number
|
|
37
|
+
total: number
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type ContextEvents = {
|
|
42
|
+
update: Usage
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class ZaiContext {
|
|
46
|
+
private _startedAt = Date.now()
|
|
47
|
+
|
|
48
|
+
private _inputCost = 0
|
|
49
|
+
private _outputCost = 0
|
|
50
|
+
private _inputTokens = 0
|
|
51
|
+
private _outputTokens = 0
|
|
52
|
+
private _totalCachedResponses = 0
|
|
53
|
+
|
|
54
|
+
private _totalRequests = 0
|
|
55
|
+
private _totalErrors = 0
|
|
56
|
+
private _totalResponses = 0
|
|
57
|
+
|
|
58
|
+
public taskId: string
|
|
59
|
+
public taskType: string
|
|
60
|
+
public modelId: GenerateContentInput['model']
|
|
61
|
+
public adapter?: Adapter
|
|
62
|
+
public source?: GenerateContentInput['meta']
|
|
63
|
+
|
|
64
|
+
private _eventEmitter: EventEmitter<ContextEvents>
|
|
65
|
+
|
|
66
|
+
public controller: AbortController = new AbortController()
|
|
67
|
+
private _client: Cognitive
|
|
68
|
+
|
|
69
|
+
public constructor(props: ZaiContextProps) {
|
|
70
|
+
this._client = props.client.clone()
|
|
71
|
+
this.taskId = props.taskId
|
|
72
|
+
this.modelId = props.modelId
|
|
73
|
+
this.adapter = props.adapter
|
|
74
|
+
this.source = props.source
|
|
75
|
+
this.taskType = props.taskType
|
|
76
|
+
this._eventEmitter = new EventEmitter<ContextEvents>()
|
|
77
|
+
|
|
78
|
+
this._client.on('request', () => {
|
|
79
|
+
this._totalRequests++
|
|
80
|
+
this._eventEmitter.emit('update', this.usage)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
this._client.on('response', (_req, res) => {
|
|
84
|
+
this._totalResponses++
|
|
85
|
+
|
|
86
|
+
if (res.meta.cached) {
|
|
87
|
+
this._totalCachedResponses++
|
|
88
|
+
} else {
|
|
89
|
+
this._inputTokens += res.meta.tokens.input || 0
|
|
90
|
+
this._outputTokens += res.meta.tokens.output || 0
|
|
91
|
+
this._inputCost += res.meta.cost.input || 0
|
|
92
|
+
this._outputCost += res.meta.cost.output || 0
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
this._eventEmitter.emit('update', this.usage)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
this._client.on('error', () => {
|
|
99
|
+
this._totalErrors++
|
|
100
|
+
this._eventEmitter.emit('update', this.usage)
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public async getModel(): Promise<Model> {
|
|
105
|
+
return this._client.getModelDetails(this.modelId)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public on<K extends keyof ContextEvents>(type: K, listener: (event: ContextEvents[K]) => void) {
|
|
109
|
+
this._eventEmitter.on(type, listener)
|
|
110
|
+
return this
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
public clear() {
|
|
114
|
+
this._eventEmitter.clear()
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
public async generateContent<Out = string>(
|
|
118
|
+
props: GenerateContentProps<Out>
|
|
119
|
+
): Promise<{ meta: Meta; output: GenerateContentOutput; text: string | undefined; extracted: Out }> {
|
|
120
|
+
const maxRetries = Math.max(props.maxRetries ?? 3, 0)
|
|
121
|
+
const transform = props.transform
|
|
122
|
+
let lastError: Error | null = null
|
|
123
|
+
const messages = [...(props.messages || [])]
|
|
124
|
+
|
|
125
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
126
|
+
try {
|
|
127
|
+
const response = await this._client.generateContent({
|
|
128
|
+
...props,
|
|
129
|
+
messages,
|
|
130
|
+
signal: this.controller.signal,
|
|
131
|
+
model: this.modelId,
|
|
132
|
+
meta: {
|
|
133
|
+
integrationName: props.meta?.integrationName || 'zai',
|
|
134
|
+
promptCategory: props.meta?.promptCategory || `zai:${this.taskType}`,
|
|
135
|
+
promptSource: props.meta?.promptSource || `zai:${this.taskType}:${this.taskId ?? 'default'}`,
|
|
136
|
+
},
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
const content = response.output.choices[0]?.content
|
|
140
|
+
const str = typeof content === 'string' ? content : content?.[0]?.text || ''
|
|
141
|
+
let output: Out
|
|
142
|
+
|
|
143
|
+
messages.push({
|
|
144
|
+
role: 'assistant',
|
|
145
|
+
content: str || '<Invalid output, no content provided>',
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
if (!transform) {
|
|
149
|
+
output = str as any
|
|
150
|
+
} else {
|
|
151
|
+
output = transform(str, response.output)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return { meta: response.meta, output: response.output, text: str, extracted: output }
|
|
155
|
+
} catch (error) {
|
|
156
|
+
lastError = error as Error
|
|
157
|
+
|
|
158
|
+
if (attempt === maxRetries) {
|
|
159
|
+
throw lastError
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
messages.push({
|
|
163
|
+
role: 'user',
|
|
164
|
+
content: `ERROR PARSING OUTPUT\n\n${lastError.message}.\n\nPlease return a valid response addressing the error above.`,
|
|
165
|
+
})
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
throw lastError
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
public get elapsedTime(): number {
|
|
173
|
+
return Date.now() - this._startedAt
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
public get usage(): Usage {
|
|
177
|
+
return {
|
|
178
|
+
requests: {
|
|
179
|
+
errors: this._totalErrors,
|
|
180
|
+
requests: this._totalRequests,
|
|
181
|
+
responses: this._totalResponses,
|
|
182
|
+
cached: this._totalCachedResponses,
|
|
183
|
+
percentage: this._totalRequests > 0 ? (this._totalResponses + this._totalErrors) / this._totalRequests : 0,
|
|
184
|
+
},
|
|
185
|
+
tokens: {
|
|
186
|
+
input: this._inputTokens,
|
|
187
|
+
output: this._outputTokens,
|
|
188
|
+
total: this._inputTokens + this._outputTokens,
|
|
189
|
+
},
|
|
190
|
+
cost: {
|
|
191
|
+
input: this._inputCost,
|
|
192
|
+
output: this._outputCost,
|
|
193
|
+
total: this._inputCost + this._outputCost,
|
|
194
|
+
},
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
package/src/emitter.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export class EventEmitter<E extends object> {
|
|
2
|
+
private _listeners: {
|
|
3
|
+
[K in keyof E]?: ((event: E[K]) => void)[]
|
|
4
|
+
} = {}
|
|
5
|
+
|
|
6
|
+
public emit<K extends keyof E>(type: K, event: E[K]) {
|
|
7
|
+
const listeners = this._listeners[type]
|
|
8
|
+
if (!listeners) {
|
|
9
|
+
return
|
|
10
|
+
}
|
|
11
|
+
for (const listener of listeners) {
|
|
12
|
+
listener(event)
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public once<K extends keyof E>(type: K, listener: (event: E[K]) => void) {
|
|
17
|
+
const wrapped = (event: E[K]) => {
|
|
18
|
+
this.off(type, wrapped)
|
|
19
|
+
listener(event)
|
|
20
|
+
}
|
|
21
|
+
this.on(type, wrapped)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public on<K extends keyof E>(type: K, listener: (event: E[K]) => void) {
|
|
25
|
+
if (!this._listeners[type]) {
|
|
26
|
+
this._listeners[type] = []
|
|
27
|
+
}
|
|
28
|
+
this._listeners[type]!.push(listener)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public off<K extends keyof E>(type: K, listener: (event: E[K]) => void) {
|
|
32
|
+
const listeners = this._listeners[type]
|
|
33
|
+
if (!listeners) {
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
const index = listeners.indexOf(listener)
|
|
37
|
+
if (index !== -1) {
|
|
38
|
+
listeners.splice(index, 1)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public clear<K extends keyof E>(type?: K) {
|
|
43
|
+
if (type) {
|
|
44
|
+
delete this._listeners[type]
|
|
45
|
+
} else {
|
|
46
|
+
this._listeners = {}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
package/src/operations/check.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
// eslint-disable consistent-type-definitions
|
|
2
2
|
import { z } from '@bpinternal/zui'
|
|
3
3
|
|
|
4
|
+
import { ZaiContext } from '../context'
|
|
5
|
+
import { Response } from '../response'
|
|
6
|
+
import { getTokenizer } from '../tokenizer'
|
|
4
7
|
import { fastHash, stringify, takeUntilTokens } from '../utils'
|
|
5
8
|
import { Zai } from '../zai'
|
|
6
9
|
import { PROMPT_INPUT_BUFFER } from './constants'
|
|
@@ -35,12 +38,15 @@ declare module '@botpress/zai' {
|
|
|
35
38
|
input: unknown,
|
|
36
39
|
condition: string,
|
|
37
40
|
options?: Options
|
|
38
|
-
):
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
): Response<
|
|
42
|
+
{
|
|
43
|
+
/** Whether the condition is true or not */
|
|
44
|
+
value: boolean
|
|
45
|
+
/** The explanation of the decision */
|
|
46
|
+
explanation: string
|
|
47
|
+
},
|
|
48
|
+
boolean
|
|
49
|
+
>
|
|
44
50
|
}
|
|
45
51
|
}
|
|
46
52
|
|
|
@@ -48,13 +54,21 @@ const TRUE = '■TRUE■'
|
|
|
48
54
|
const FALSE = '■FALSE■'
|
|
49
55
|
const END = '■END■'
|
|
50
56
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
const check = async (
|
|
58
|
+
input: unknown,
|
|
59
|
+
condition: string,
|
|
60
|
+
options: Options,
|
|
61
|
+
ctx: ZaiContext
|
|
62
|
+
): Promise<{
|
|
63
|
+
value: boolean
|
|
64
|
+
explanation: string
|
|
65
|
+
}> => {
|
|
66
|
+
ctx.controller.signal.throwIfAborted()
|
|
67
|
+
const tokenizer = await getTokenizer()
|
|
68
|
+
const model = await ctx.getModel()
|
|
69
|
+
const PROMPT_COMPONENT = Math.max(model.input.maxTokens - PROMPT_INPUT_BUFFER, 100)
|
|
70
|
+
|
|
71
|
+
const taskId = ctx.taskId
|
|
58
72
|
const taskType = 'zai.check'
|
|
59
73
|
|
|
60
74
|
const PROMPT_TOKENS = {
|
|
@@ -78,13 +92,14 @@ Zai.prototype.check = async function (this: Zai, input: unknown, condition: stri
|
|
|
78
92
|
})
|
|
79
93
|
)
|
|
80
94
|
|
|
81
|
-
const examples =
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
95
|
+
const examples =
|
|
96
|
+
taskId && ctx.adapter
|
|
97
|
+
? await ctx.adapter.getExamples<string, boolean>({
|
|
98
|
+
input: inputAsString,
|
|
99
|
+
taskType,
|
|
100
|
+
taskId,
|
|
101
|
+
})
|
|
102
|
+
: []
|
|
88
103
|
|
|
89
104
|
const exactMatch = examples.find((x) => x.key === Key)
|
|
90
105
|
if (exactMatch) {
|
|
@@ -163,7 +178,10 @@ ${END}
|
|
|
163
178
|
`.trim()
|
|
164
179
|
: ''
|
|
165
180
|
|
|
166
|
-
const {
|
|
181
|
+
const {
|
|
182
|
+
extracted: { finalAnswer, explanation },
|
|
183
|
+
meta,
|
|
184
|
+
} = await ctx.generateContent({
|
|
167
185
|
systemPrompt: `
|
|
168
186
|
Check if the following condition is true or false for the given input. Before answering, make sure to read the input and the condition carefully.
|
|
169
187
|
Justify your answer, then answer with either ${TRUE} or ${FALSE} at the very end, then add ${END} to finish the response.
|
|
@@ -184,35 +202,36 @@ In your "Analysis", please refer to the Expert Examples # to justify your decisi
|
|
|
184
202
|
role: 'user',
|
|
185
203
|
},
|
|
186
204
|
],
|
|
205
|
+
transform: (text) => {
|
|
206
|
+
const hasTrue = text.includes(TRUE)
|
|
207
|
+
const hasFalse = text.includes(FALSE)
|
|
208
|
+
|
|
209
|
+
if (!hasTrue && !hasFalse) {
|
|
210
|
+
throw new Error(`The model did not return a valid answer. The response was: ${text}`)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
let finalAnswer: boolean
|
|
214
|
+
const explanation = text
|
|
215
|
+
.replace(TRUE, '')
|
|
216
|
+
.replace(FALSE, '')
|
|
217
|
+
.replace(END, '')
|
|
218
|
+
.replace('Final Answer:', '')
|
|
219
|
+
.replace('Analysis:', '')
|
|
220
|
+
.trim()
|
|
221
|
+
|
|
222
|
+
if (hasTrue && hasFalse) {
|
|
223
|
+
// If both TRUE and FALSE are present, we need to check which one was answered last
|
|
224
|
+
finalAnswer = text.lastIndexOf(TRUE) > text.lastIndexOf(FALSE)
|
|
225
|
+
} else {
|
|
226
|
+
finalAnswer = hasTrue
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return { finalAnswer, explanation: explanation.trim() }
|
|
230
|
+
},
|
|
187
231
|
})
|
|
188
232
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const hasTrue = answer.includes(TRUE)
|
|
192
|
-
const hasFalse = answer.includes(FALSE)
|
|
193
|
-
|
|
194
|
-
if (!hasTrue && !hasFalse) {
|
|
195
|
-
throw new Error(`The model did not return a valid answer. The response was: ${answer}`)
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
let finalAnswer: boolean
|
|
199
|
-
const explanation = answer
|
|
200
|
-
.replace(TRUE, '')
|
|
201
|
-
.replace(FALSE, '')
|
|
202
|
-
.replace(END, '')
|
|
203
|
-
.replace('Final Answer:', '')
|
|
204
|
-
.replace('Analysis:', '')
|
|
205
|
-
.trim()
|
|
206
|
-
|
|
207
|
-
if (hasTrue && hasFalse) {
|
|
208
|
-
// If both TRUE and FALSE are present, we need to check which one was answered last
|
|
209
|
-
finalAnswer = answer.lastIndexOf(TRUE) > answer.lastIndexOf(FALSE)
|
|
210
|
-
} else {
|
|
211
|
-
finalAnswer = hasTrue
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (taskId) {
|
|
215
|
-
await this.adapter.saveExample({
|
|
233
|
+
if (taskId && ctx.adapter && !ctx.controller.signal.aborted) {
|
|
234
|
+
await ctx.adapter.saveExample({
|
|
216
235
|
key: Key,
|
|
217
236
|
taskType,
|
|
218
237
|
taskId,
|
|
@@ -224,7 +243,7 @@ In your "Analysis", please refer to the Expert Examples # to justify your decisi
|
|
|
224
243
|
output: meta.cost.output,
|
|
225
244
|
},
|
|
226
245
|
latency: meta.latency,
|
|
227
|
-
model:
|
|
246
|
+
model: ctx.modelId,
|
|
228
247
|
tokens: {
|
|
229
248
|
input: meta.tokens.input,
|
|
230
249
|
output: meta.tokens.output,
|
|
@@ -240,3 +259,34 @@ In your "Analysis", please refer to the Expert Examples # to justify your decisi
|
|
|
240
259
|
explanation: explanation.trim(),
|
|
241
260
|
}
|
|
242
261
|
}
|
|
262
|
+
|
|
263
|
+
Zai.prototype.check = function (
|
|
264
|
+
this: Zai,
|
|
265
|
+
input: unknown,
|
|
266
|
+
condition: string,
|
|
267
|
+
_options: Options | undefined
|
|
268
|
+
): Response<
|
|
269
|
+
{
|
|
270
|
+
value: boolean
|
|
271
|
+
explanation: string
|
|
272
|
+
},
|
|
273
|
+
boolean
|
|
274
|
+
> {
|
|
275
|
+
const options = _Options.parse(_options ?? {}) as Options
|
|
276
|
+
|
|
277
|
+
const context = new ZaiContext({
|
|
278
|
+
client: this.client,
|
|
279
|
+
modelId: this.Model,
|
|
280
|
+
taskId: this.taskId,
|
|
281
|
+
taskType: 'zai.check',
|
|
282
|
+
adapter: this.adapter,
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
return new Response<
|
|
286
|
+
{
|
|
287
|
+
value: boolean
|
|
288
|
+
explanation: string
|
|
289
|
+
},
|
|
290
|
+
boolean
|
|
291
|
+
>(context, check(input, condition, options, context), (result) => result.value)
|
|
292
|
+
}
|