@botpress/adk-cli 1.19.0-beta.4 → 1.19.0-beta.5
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/{README-wjb7z7f0.md → README-824wa4jj.md} +1 -1
- package/dist/SKILL-75ym6tcj.md +257 -0
- package/dist/SKILL-chnwzmt1.md +548 -0
- package/dist/SKILL-d4bs53y3.md +244 -0
- package/dist/SKILL-h4b2f1n9.md +114 -0
- package/dist/SKILL-hbw5nt95.md +111 -0
- package/dist/actions-h7hxxvxr.md +823 -0
- package/dist/adk-build-emhwd0tg.md +39 -0
- package/dist/adk-debug-yrrdtpmb.md +23 -0
- package/dist/adk-dev-console-7z9rtjpy.md +17 -0
- package/dist/adk-document-ras6zzzh.md +68 -0
- package/dist/adk-eval-vx76dwq0.md +17 -0
- package/dist/adk-explain-fcsaw852.md +22 -0
- package/dist/adk-init-9kmxmbbe.md +30 -0
- package/dist/adk-ship-dybzn884.md +29 -0
- package/dist/adk-test-xq67savs.md +27 -0
- package/dist/adk-validate-1p4skv4m.md +31 -0
- package/dist/advanced-patterns-z86m9h1a.md +669 -0
- package/dist/agent-config-1aqvkrgf.md +450 -0
- package/dist/agent-steps-zj4c1n9t.md +115 -0
- package/dist/assets-q7jt8r2q.md +237 -0
- package/dist/autonomous-execution-fymc12e5.md +747 -0
- package/dist/cli-c31e06yr.md +1334 -0
- package/dist/cli.js +970 -566
- package/dist/commands.json +24 -3
- package/dist/common-failures-ht29w2db.md +231 -0
- package/dist/component-registry-bbpw0see.md +43 -0
- package/dist/context-api-760cvh0h.md +461 -0
- package/dist/conversation-analysis-8ka4nrm4.md +420 -0
- package/dist/conversation-lifecycle-4seqqjc1.md +311 -0
- package/dist/conversations-gwfvxaee.md +1111 -0
- package/dist/custom-components-y5wdgpey.md +167 -0
- package/dist/debug-workflow-vz84q80v.md +239 -0
- package/dist/desk-k54ktvsd.md +852 -0
- package/dist/doc-standards-ck6ax2jd.md +124 -0
- package/dist/eval-format-7n9brja4.md +354 -0
- package/dist/evals-y1zcr1mc.md +11 -0
- package/dist/explain-config-1yaq3zzd.md +424 -0
- package/dist/files-dzt0wxn3.md +918 -0
- package/dist/integration-actions-xang7tma.md +659 -0
- package/dist/integrations-k5ss07f4.md +266 -0
- package/dist/interfaces-6t0bpxs4.md +97 -0
- package/dist/knowledge-bases-20rg8p5c.md +456 -0
- package/dist/llm-debugging-76ng8rzm.md +209 -0
- package/dist/mcp-server-n1asyzhv.md +112 -0
- package/dist/messages-gkkg0b54.md +769 -0
- package/dist/model-configuration-f273kgd0.md +201 -0
- package/dist/multi-agent-dashboard-1mdfjdts.md +70 -0
- package/dist/pages-xn18xn73.md +273 -0
- package/dist/patterns-mistakes-5vb99dhf.md +469 -0
- package/dist/plugins-ttnx8f49.md +280 -0
- package/dist/tables-x45t36dd.md +1136 -0
- package/dist/tags-46td3qrg.md +516 -0
- package/dist/test-patterns-hj47w4nc.md +355 -0
- package/dist/testing-workflow-2vkp932f.md +225 -0
- package/dist/tools-wk7bq24z.md +581 -0
- package/dist/trace-summarization-hdyx1c2e.md +313 -0
- package/dist/traces-and-logs-f2kjfh19.md +203 -0
- package/dist/triggers-4j2cc86x.md +719 -0
- package/dist/ui-server-entry.js +952 -137
- package/dist/workflow-steps-mrdrf1c5.md +851 -0
- package/dist/workflows-gadx3s69.md +1408 -0
- package/dist/zai-agent-reference-e6644aad.md +454 -0
- package/dist/zai-complete-guide-mnna5d6f.md +1408 -0
- package/package.json +4 -4
|
@@ -0,0 +1,1408 @@
|
|
|
1
|
+
# ZAI: Complete Developer Guide
|
|
2
|
+
|
|
3
|
+
ZAI (Zui AI) is Botpress's production-ready LLM utility library that provides a clean, type-safe API for common AI operations. Built on Zod schemas and the Botpress Cognitive API, it makes AI operations simple, intuitive, and scalable.
|
|
4
|
+
|
|
5
|
+
## Part I: Developer Usage
|
|
6
|
+
|
|
7
|
+
### 1. Getting Started
|
|
8
|
+
|
|
9
|
+
#### Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @botpress/zai @botpress/client @bpinternal/zui
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
#### Basic Setup
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { Client } from "@botpress/client";
|
|
19
|
+
import { Zai } from "@botpress/zai";
|
|
20
|
+
import { z } from "@bpinternal/zui";
|
|
21
|
+
|
|
22
|
+
// Initialize Botpress client
|
|
23
|
+
const client = new Client({
|
|
24
|
+
botId: "YOUR_BOT_ID",
|
|
25
|
+
token: "YOUR_TOKEN",
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Create ZAI instance
|
|
29
|
+
const zai = new Zai({ client });
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
#### Configuration Options
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
const zai = new Zai({
|
|
36
|
+
client, // Required: Botpress client or Cognitive instance
|
|
37
|
+
modelId: "best", // Model selection: 'best' | 'fast' | specific model ID
|
|
38
|
+
userId: "user-123", // Optional: Track usage per user
|
|
39
|
+
namespace: "my-app", // Default: 'zai'
|
|
40
|
+
activeLearning: {
|
|
41
|
+
// Enable learning from examples
|
|
42
|
+
enable: true,
|
|
43
|
+
tableName: "AILearningTable",
|
|
44
|
+
taskId: "sentiment-analysis",
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 2. Core Operations
|
|
50
|
+
|
|
51
|
+
#### 2.1 Extract - Structured Data Extraction
|
|
52
|
+
|
|
53
|
+
Extract structured data from any input using Zod schemas. Located in `/packages/zai/src/operations/extract.ts`.
|
|
54
|
+
|
|
55
|
+
**Basic Object Extraction:**
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
const person = await zai.extract(
|
|
59
|
+
"John Doe is 30 years old and lives in New York",
|
|
60
|
+
z.object({
|
|
61
|
+
name: z.string(),
|
|
62
|
+
age: z.number(),
|
|
63
|
+
location: z.string(),
|
|
64
|
+
}),
|
|
65
|
+
);
|
|
66
|
+
// Result: { name: 'John Doe', age: 30, location: 'New York' }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Array Extraction:**
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
const products = await zai.extract(
|
|
73
|
+
productCatalogText,
|
|
74
|
+
z.array(
|
|
75
|
+
z.object({
|
|
76
|
+
name: z.string(),
|
|
77
|
+
price: z.number(),
|
|
78
|
+
inStock: z.boolean(),
|
|
79
|
+
}),
|
|
80
|
+
),
|
|
81
|
+
);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Advanced Options:**
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
const data = await zai.extract(input, schema, {
|
|
88
|
+
instructions: "Focus on technical specifications", // Guide extraction
|
|
89
|
+
chunkLength: 8000, // Max tokens per chunk (default: 16000)
|
|
90
|
+
strict: false, // Allow partial matches
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**Large Document Handling:**
|
|
95
|
+
ZAI automatically handles documents of any size through intelligent chunking:
|
|
96
|
+
|
|
97
|
+
- Documents over `chunkLength` are split into chunks
|
|
98
|
+
- Each chunk is processed in parallel
|
|
99
|
+
- Results are intelligently merged
|
|
100
|
+
|
|
101
|
+
#### 2.2 Check - Boolean Verification
|
|
102
|
+
|
|
103
|
+
Verify conditions with natural language. Located in `/packages/zai/src/operations/check.ts`.
|
|
104
|
+
|
|
105
|
+
**Simple Check:**
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
const isSpam = await zai.check("Win FREE iPhone!!!", "is spam");
|
|
109
|
+
// Result: true
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Detailed Results:**
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
const result = await zai.check(email, "contains personal information");
|
|
116
|
+
const { value, explanation } = await result.full();
|
|
117
|
+
// value: true
|
|
118
|
+
// explanation: "The email contains names, addresses, and phone numbers"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**With Examples:**
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
const isValid = await zai.check(code, "is valid JavaScript", {
|
|
125
|
+
examples: [
|
|
126
|
+
{ input: "const x = 1", check: true, reason: "Valid const declaration" },
|
|
127
|
+
{ input: "const = 1", check: false, reason: "Missing variable name" },
|
|
128
|
+
],
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
#### 2.3 Label - Multi-Label Classification
|
|
133
|
+
|
|
134
|
+
Apply multiple labels simultaneously. Located in `/packages/zai/src/operations/label.ts`.
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
const labels = await zai.label(customerReview, {
|
|
138
|
+
positive: "expresses positive sentiment",
|
|
139
|
+
technical: "mentions technical specifications",
|
|
140
|
+
verified: "from a verified purchaser",
|
|
141
|
+
urgent: "requires immediate attention",
|
|
142
|
+
});
|
|
143
|
+
// Result: { positive: true, technical: true, verified: false, urgent: false }
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Each label gets its own explanation:
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
const result = await zai.label(text, criteria);
|
|
150
|
+
const detailed = await result.full();
|
|
151
|
+
// detailed.positive = { value: true, explanation: "User says 'excellent product'" }
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
#### 2.4 Rewrite - Text Transformation
|
|
155
|
+
|
|
156
|
+
Transform text according to instructions. Located in `/packages/zai/src/operations/rewrite.ts`.
|
|
157
|
+
|
|
158
|
+
**Translation:**
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
const french = await zai.rewrite(englishText, "translate to French");
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**Tone Adjustment:**
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
const professional = await zai.rewrite(
|
|
168
|
+
"hey whats up? need that report asap!!",
|
|
169
|
+
"make it professional and polite",
|
|
170
|
+
);
|
|
171
|
+
// "Good morning, I hope this message finds you well.
|
|
172
|
+
// Could you please provide the report at your earliest convenience?"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Format Conversion:**
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
const markdown = await zai.rewrite(htmlContent, "convert to Markdown format");
|
|
179
|
+
const json = await zai.rewrite(csvData, "convert to JSON array");
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
#### 2.5 Filter - Array Filtering
|
|
183
|
+
|
|
184
|
+
Filter arrays using natural language conditions. Located in `/packages/zai/src/operations/filter.ts`.
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
const companies = [
|
|
188
|
+
{ name: "Apple", industry: "Tech", revenue: 365 },
|
|
189
|
+
{ name: "Ford", industry: "Auto", revenue: 156 },
|
|
190
|
+
{ name: "Google", industry: "Tech", revenue: 282 },
|
|
191
|
+
];
|
|
192
|
+
|
|
193
|
+
const techGiants = await zai.filter(
|
|
194
|
+
companies,
|
|
195
|
+
"are technology companies with revenue over 200 billion",
|
|
196
|
+
);
|
|
197
|
+
// Result: [Apple, Google]
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Complex Filtering:**
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
const eligibleUsers = await zai.filter(
|
|
204
|
+
users,
|
|
205
|
+
`
|
|
206
|
+
- Have verified email
|
|
207
|
+
- Account created more than 30 days ago
|
|
208
|
+
- No recent violations
|
|
209
|
+
- Located in North America
|
|
210
|
+
`,
|
|
211
|
+
);
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
#### 2.6 Text - Content Generation
|
|
215
|
+
|
|
216
|
+
Generate text from prompts. Located in `/packages/zai/src/operations/text.ts`.
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
const blogPost = await zai.text("Write about the future of AI in healthcare", {
|
|
220
|
+
length: 1000, // Target length in tokens
|
|
221
|
+
temperature: 0.7, // Creativity (0-1)
|
|
222
|
+
stopSequences: ["---"], // Optional stop markers
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Structured Generation:**
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
const outline = await zai.text(`
|
|
230
|
+
Create a detailed course outline for:
|
|
231
|
+
- Topic: Machine Learning
|
|
232
|
+
- Level: Beginner
|
|
233
|
+
- Duration: 8 weeks
|
|
234
|
+
- Format: Online
|
|
235
|
+
`);
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
#### 2.7 Summarize - Document Summarization
|
|
239
|
+
|
|
240
|
+
Create intelligent summaries. Located in `/packages/zai/src/operations/summarize.ts`.
|
|
241
|
+
|
|
242
|
+
**Basic Summary:**
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
const summary = await zai.summarize(longArticle);
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**Custom Summaries:**
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
const technicalSummary = await zai.summarize(researchPaper, {
|
|
252
|
+
length: 500, // Max tokens
|
|
253
|
+
prompt: "Focus on methodology and results",
|
|
254
|
+
bulletPoints: true, // Format as bullet points
|
|
255
|
+
});
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**Handling Large Documents:**
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
// ZAI automatically handles documents of any size
|
|
262
|
+
const bookSummary = await zai.summarize(entireBook, {
|
|
263
|
+
length: 2000,
|
|
264
|
+
prompt: "Summarize each chapter separately, then provide overall themes",
|
|
265
|
+
});
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
#### 2.8 Answer - Question Answering with Citations
|
|
269
|
+
|
|
270
|
+
Answer questions from documents with citations and intelligent edge case handling. Located in `/packages/zai/src/operations/answer.ts`.
|
|
271
|
+
|
|
272
|
+
**Basic Usage:**
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
const documents = [
|
|
276
|
+
"Botpress was founded in 2016.",
|
|
277
|
+
"The company is based in Quebec, Canada.",
|
|
278
|
+
"Botpress provides an AI agent platform.",
|
|
279
|
+
];
|
|
280
|
+
|
|
281
|
+
const result = await zai.answer(documents, "When was Botpress founded?");
|
|
282
|
+
if (result.type === "answer") {
|
|
283
|
+
console.log(result.answer); // "Botpress was founded in 2016."
|
|
284
|
+
console.log(result.citations); // Citations with source references
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**Response Types:**
|
|
289
|
+
|
|
290
|
+
The answer operation returns different types based on the situation:
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
const result = await zai.answer(documents, question);
|
|
294
|
+
|
|
295
|
+
switch (result.type) {
|
|
296
|
+
case "answer":
|
|
297
|
+
// Has answer with citations
|
|
298
|
+
console.log(result.answer);
|
|
299
|
+
console.log(result.citations); // [{ offset, item, snippet }]
|
|
300
|
+
break;
|
|
301
|
+
|
|
302
|
+
case "ambiguous":
|
|
303
|
+
// Multiple interpretations exist
|
|
304
|
+
console.log(result.ambiguity); // Why it's ambiguous
|
|
305
|
+
console.log(result.follow_up); // Clarifying question
|
|
306
|
+
console.log(result.answers); // Possible answers
|
|
307
|
+
break;
|
|
308
|
+
|
|
309
|
+
case "out_of_topic":
|
|
310
|
+
// Question unrelated to documents
|
|
311
|
+
console.log(result.reason);
|
|
312
|
+
break;
|
|
313
|
+
|
|
314
|
+
case "invalid_question":
|
|
315
|
+
// Malformed or unclear question
|
|
316
|
+
console.log(result.reason);
|
|
317
|
+
break;
|
|
318
|
+
|
|
319
|
+
case "missing_knowledge":
|
|
320
|
+
// Insufficient information to answer
|
|
321
|
+
console.log(result.reason);
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**With Custom Instructions:**
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
const result = await zai.answer(documents, "What is the pricing?", {
|
|
330
|
+
instructions: "Provide detailed pricing breakdown including all tiers",
|
|
331
|
+
chunkLength: 8000, // Process in smaller chunks
|
|
332
|
+
examples: [...], // Few-shot examples
|
|
333
|
+
});
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
**Tracking Citations:**
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
if (result.type === "answer") {
|
|
340
|
+
result.citations.forEach((citation) => {
|
|
341
|
+
console.log(`At position ${citation.offset}:`);
|
|
342
|
+
console.log(` Cited: "${citation.snippet}"`);
|
|
343
|
+
console.log(` From document:`, citation.item);
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
#### 2.9 Rate - Array Rating
|
|
349
|
+
|
|
350
|
+
Rate array items on a 1-5 scale based on criteria. Located in `/packages/zai/src/operations/rate.ts`.
|
|
351
|
+
|
|
352
|
+
**Single Criterion:**
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
const emails = [
|
|
356
|
+
/* array of emails */
|
|
357
|
+
];
|
|
358
|
+
const urgencyScores = await zai.rate(emails, "urgency level");
|
|
359
|
+
// Result: [4, 2, 5, 1, 3] // Numbers 1-5
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**Multiple Criteria:**
|
|
363
|
+
|
|
364
|
+
```typescript
|
|
365
|
+
const products = [
|
|
366
|
+
/* array of products */
|
|
367
|
+
];
|
|
368
|
+
const ratings = await zai.rate(products, {
|
|
369
|
+
quality: "product build quality",
|
|
370
|
+
value: "price to performance ratio",
|
|
371
|
+
design: "aesthetic appeal",
|
|
372
|
+
});
|
|
373
|
+
// Result: [
|
|
374
|
+
// { quality: 5, value: 4, design: 5, total: 14 },
|
|
375
|
+
// { quality: 3, value: 5, design: 4, total: 12 },
|
|
376
|
+
// ...
|
|
377
|
+
// ]
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
**With Options:**
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
const rated = await zai.rate(items, instructions, {
|
|
384
|
+
tokensPerItem: 250, // Max tokens per item
|
|
385
|
+
maxItemsPerChunk: 50, // Items per batch
|
|
386
|
+
});
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
#### 2.10 Sort - Natural Language Sorting
|
|
390
|
+
|
|
391
|
+
Sort arrays based on natural language instructions. Located in `/packages/zai/src/operations/sort.ts`.
|
|
392
|
+
|
|
393
|
+
**Basic Sorting:**
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
const sorted = await zai.sort(tickets, "from least urgent to most urgent");
|
|
397
|
+
const byPrice = await zai.sort(products, "by price, cheapest first");
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
**Priority-Based Sorting:**
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
const prioritized = await zai.sort(
|
|
404
|
+
emails,
|
|
405
|
+
"prioritize: open old items highest",
|
|
406
|
+
);
|
|
407
|
+
// First item = highest priority, last = lowest priority
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
**Complex Sorting:**
|
|
411
|
+
|
|
412
|
+
```typescript
|
|
413
|
+
const sorted = await zai.sort(
|
|
414
|
+
applications,
|
|
415
|
+
`
|
|
416
|
+
Sort by:
|
|
417
|
+
1. Completeness (complete applications first)
|
|
418
|
+
2. Submission date (newer first)
|
|
419
|
+
3. Applicant experience (more experienced first)
|
|
420
|
+
`,
|
|
421
|
+
);
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
**With Options:**
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
const sorted = await zai.sort(items, instructions, {
|
|
428
|
+
tokensPerItem: 250, // Max tokens per item
|
|
429
|
+
});
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
#### 2.11 Group - Array Grouping
|
|
433
|
+
|
|
434
|
+
Group array elements based on natural language criteria. Located in `/packages/zai/src/operations/group.ts`.
|
|
435
|
+
|
|
436
|
+
**Basic Grouping:**
|
|
437
|
+
|
|
438
|
+
```typescript
|
|
439
|
+
const groups = await zai.group(tickets, {
|
|
440
|
+
instructions: "group by issue type and priority",
|
|
441
|
+
});
|
|
442
|
+
// Result: [
|
|
443
|
+
// { id: 'bugs', label: 'Bug Reports', elements: [...] },
|
|
444
|
+
// { id: 'features', label: 'Feature Requests', elements: [...] },
|
|
445
|
+
// { id: 'urgent', label: 'Urgent Issues', elements: [...] }
|
|
446
|
+
// ]
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
**With Initial Groups:**
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
452
|
+
const groups = await zai.group(emails, {
|
|
453
|
+
instructions: "categorize emails",
|
|
454
|
+
initialGroups: [
|
|
455
|
+
{ id: "urgent", label: "Urgent" },
|
|
456
|
+
{ id: "spam", label: "Spam" },
|
|
457
|
+
{ id: "normal", label: "Normal" },
|
|
458
|
+
],
|
|
459
|
+
});
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
**Access Results:**
|
|
463
|
+
|
|
464
|
+
```typescript
|
|
465
|
+
// As groups array
|
|
466
|
+
const groups = await zai.group(items, options);
|
|
467
|
+
for (const group of groups) {
|
|
468
|
+
console.log(`${group.label}: ${group.elements.length} items`);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// As dictionary (using .result())
|
|
472
|
+
const { output } = await zai.group(items, options).result();
|
|
473
|
+
// output is Record<string, T[]>
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
**With Options:**
|
|
477
|
+
|
|
478
|
+
```typescript
|
|
479
|
+
const groups = await zai.group(items, {
|
|
480
|
+
instructions: "group by category",
|
|
481
|
+
tokensPerElement: 250, // Max tokens per element
|
|
482
|
+
chunkLength: 16000, // Max tokens per chunk
|
|
483
|
+
initialGroups: [...], // Predefined groups
|
|
484
|
+
});
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
#### 2.12 Patch - File Patching
|
|
488
|
+
|
|
489
|
+
Patch code files using natural language instructions with efficient micropatch protocol. Located in `/packages/zai/src/operations/patch.ts`.
|
|
490
|
+
|
|
491
|
+
**Basic Patching:**
|
|
492
|
+
|
|
493
|
+
```typescript
|
|
494
|
+
const files = [
|
|
495
|
+
{
|
|
496
|
+
path: "src/hello.ts",
|
|
497
|
+
name: "hello.ts",
|
|
498
|
+
content: 'console.log("Hello World")',
|
|
499
|
+
},
|
|
500
|
+
];
|
|
501
|
+
|
|
502
|
+
const patched = await zai.patch(files, 'change message to "Hi World"');
|
|
503
|
+
// Result: [{
|
|
504
|
+
// path: 'src/hello.ts',
|
|
505
|
+
// name: 'hello.ts',
|
|
506
|
+
// content: 'console.log("Hi World")',
|
|
507
|
+
// patch: '◼︎=1|console.log("Hi World")'
|
|
508
|
+
// }]
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
**Multiple Files:**
|
|
512
|
+
|
|
513
|
+
```typescript
|
|
514
|
+
const files = [
|
|
515
|
+
{ path: "package.json", name: "package.json", content: "..." },
|
|
516
|
+
{ path: "config.json", name: "config.json", content: "..." },
|
|
517
|
+
];
|
|
518
|
+
|
|
519
|
+
const patched = await zai.patch(
|
|
520
|
+
files,
|
|
521
|
+
"update version to 2.0.0 in all config files",
|
|
522
|
+
);
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
**Common Use Cases:**
|
|
526
|
+
|
|
527
|
+
```typescript
|
|
528
|
+
// Add documentation
|
|
529
|
+
await zai.patch(files, "add JSDoc comments to all exported functions");
|
|
530
|
+
|
|
531
|
+
// Remove code
|
|
532
|
+
await zai.patch(files, "remove all debug code");
|
|
533
|
+
|
|
534
|
+
// Refactoring
|
|
535
|
+
await zai.patch(files, "convert to async/await and add error handling");
|
|
536
|
+
|
|
537
|
+
// Type annotations
|
|
538
|
+
await zai.patch(files, "add TypeScript types to all function parameters");
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
**Inspect Applied Patches:**
|
|
542
|
+
|
|
543
|
+
```typescript
|
|
544
|
+
const patched = await zai.patch(files, instructions);
|
|
545
|
+
for (const file of patched) {
|
|
546
|
+
if (file.patch) {
|
|
547
|
+
console.log(`Patches for ${file.path}:`);
|
|
548
|
+
console.log(file.patch); // Micropatch operations
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
**With Options:**
|
|
554
|
+
|
|
555
|
+
```typescript
|
|
556
|
+
const patched = await zai.patch(files, instructions, {
|
|
557
|
+
maxTokensPerChunk: 16000, // Max tokens per processing chunk
|
|
558
|
+
});
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
### 3. Advanced Features
|
|
562
|
+
|
|
563
|
+
#### 3.1 Active Learning
|
|
564
|
+
|
|
565
|
+
Enable learning from examples to improve accuracy over time. Implementation in `/packages/zai/src/zai.ts:106-112`.
|
|
566
|
+
|
|
567
|
+
**How It Works:**
|
|
568
|
+
|
|
569
|
+
1. **Example Storage**: When enabled, ZAI stores successful operations as examples with:
|
|
570
|
+
|
|
571
|
+
- A unique hash key based on input, instructions, task type, and task ID
|
|
572
|
+
- The input and output data
|
|
573
|
+
- Metadata (tokens, cost, latency, model used)
|
|
574
|
+
- A status field (`'pending'` by default)
|
|
575
|
+
|
|
576
|
+
2. **Example Retrieval**: On subsequent operations, ZAI:
|
|
577
|
+
|
|
578
|
+
- Generates the same hash key for identical inputs
|
|
579
|
+
- Checks for exact matches (returns immediately if found - no LLM call!)
|
|
580
|
+
- Searches for similar examples using Botpress Tables API (first 1024 chars)
|
|
581
|
+
- Includes up to 10 similar examples in the prompt to guide the LLM
|
|
582
|
+
|
|
583
|
+
3. **Key Generation** (`/packages/zai/src/operations/extract.ts:182-189`):
|
|
584
|
+
|
|
585
|
+
```typescript
|
|
586
|
+
const Key = fastHash(
|
|
587
|
+
JSON.stringify({
|
|
588
|
+
taskType: "zai.extract",
|
|
589
|
+
taskId: "product-extraction",
|
|
590
|
+
input: inputAsString,
|
|
591
|
+
instructions: "Extract product details",
|
|
592
|
+
}),
|
|
593
|
+
);
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
**Configuration:**
|
|
597
|
+
|
|
598
|
+
```typescript
|
|
599
|
+
// Enable globally
|
|
600
|
+
const zai = new Zai({
|
|
601
|
+
client,
|
|
602
|
+
activeLearning: {
|
|
603
|
+
enable: true,
|
|
604
|
+
tableName: "MyLearningTable", // Must end with "Table"
|
|
605
|
+
taskId: "my-task", // Namespaced as 'zai/my-task'
|
|
606
|
+
},
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
// Enable for specific task using .learn()
|
|
610
|
+
const sentimentZai = zai.learn("sentiment-analysis");
|
|
611
|
+
const result = await sentimentZai.check(text, "is positive");
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
**Important Notes:**
|
|
615
|
+
|
|
616
|
+
- Examples are saved with `status: 'pending'` by default
|
|
617
|
+
- Only examples with `status: 'approved'` are used for learning
|
|
618
|
+
- The approval mechanism requires external implementation
|
|
619
|
+
- Without approved examples, learning is effectively disabled
|
|
620
|
+
|
|
621
|
+
**Method: `.learn(taskId)`**
|
|
622
|
+
|
|
623
|
+
Creates a new ZAI instance with active learning enabled for a specific task:
|
|
624
|
+
|
|
625
|
+
```typescript
|
|
626
|
+
// Enable for specific task
|
|
627
|
+
const sentimentZai = zai.learn("sentiment-analysis");
|
|
628
|
+
|
|
629
|
+
// What actually happens:
|
|
630
|
+
// 1. Enables active learning with the given taskId
|
|
631
|
+
// 2. Saves all operations as examples (status: 'pending')
|
|
632
|
+
// 3. Uses only 'approved' examples to improve prompts
|
|
633
|
+
// 4. WITHOUT approval, acts like caching without learning
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
**Note**: The `learn()` method enables the infrastructure but doesn't automatically approve examples. External approval is required for true learning to occur.
|
|
637
|
+
|
|
638
|
+
#### 3.1.1 Active Learning Limitations & Considerations
|
|
639
|
+
|
|
640
|
+
**Current Limitations:**
|
|
641
|
+
|
|
642
|
+
- **Manual Approval Required**: Examples default to `'pending'` status and require external approval
|
|
643
|
+
- **Search Scope**: Only first 1024 characters of input used for similarity search
|
|
644
|
+
- **Example Limit**: Maximum 10 examples retrieved per operation
|
|
645
|
+
- **No Auto-Learning**: Without approval workflow, examples accumulate but aren't used
|
|
646
|
+
|
|
647
|
+
**Storage Details:**
|
|
648
|
+
|
|
649
|
+
- Uses Botpress Tables with `'x-studio-readonly': 'true'` (read-only in Studio)
|
|
650
|
+
- Table schema includes fields for feedback and ratings (not currently used)
|
|
651
|
+
- Similarity scoring handled by Botpress Tables API, not ZAI
|
|
652
|
+
|
|
653
|
+
**Performance Impact:**
|
|
654
|
+
|
|
655
|
+
- Exact matches bypass LLM completely (instant response)
|
|
656
|
+
- Similar examples improve prompt quality but add tokens
|
|
657
|
+
- Failed operations aren't saved as examples
|
|
658
|
+
|
|
659
|
+
**Best Practices:**
|
|
660
|
+
|
|
661
|
+
- Use unique task IDs for different contexts to prevent cross-contamination
|
|
662
|
+
- Monitor table size - unused pending examples accumulate over time
|
|
663
|
+
- Consider implementing custom approval workflow if needed
|
|
664
|
+
- Test with MemoryAdapter first before using TableAdapter in production
|
|
665
|
+
|
|
666
|
+
**Example Isolation:**
|
|
667
|
+
|
|
668
|
+
```typescript
|
|
669
|
+
// Isolate learning contexts
|
|
670
|
+
const productSpamZai = zai.learn("spam-detection-products");
|
|
671
|
+
const commentSpamZai = zai.learn("spam-detection-comments");
|
|
672
|
+
|
|
673
|
+
// Each maintains separate example sets
|
|
674
|
+
const isProductSpam = await productSpamZai.check(productDesc, "is spam");
|
|
675
|
+
const isCommentSpam = await commentSpamZai.check(userComment, "is spam");
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
#### 3.2 Progress Tracking
|
|
679
|
+
|
|
680
|
+
Monitor long-running operations. Implementation in `/packages/zai/src/response.ts`.
|
|
681
|
+
|
|
682
|
+
```typescript
|
|
683
|
+
const response = zai.summarize(veryLongDocument);
|
|
684
|
+
|
|
685
|
+
// Track progress
|
|
686
|
+
response.on("progress", (progress) => {
|
|
687
|
+
console.log(`Processing: ${progress.percent}% complete`);
|
|
688
|
+
console.log(`Chunks: ${progress.completed}/${progress.total}`);
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
const summary = await response;
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
**Additional Event Methods:**
|
|
695
|
+
|
|
696
|
+
```typescript
|
|
697
|
+
// One-time event listener
|
|
698
|
+
response.once("complete", (result) => {
|
|
699
|
+
console.log("Operation finished:", result);
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
// Remove event listener
|
|
703
|
+
const handler = (progress) => console.log(progress);
|
|
704
|
+
response.on("progress", handler);
|
|
705
|
+
response.off("progress", handler);
|
|
706
|
+
|
|
707
|
+
// Connect AbortSignal for external cancellation control
|
|
708
|
+
const controller = new AbortController();
|
|
709
|
+
response.bindSignal(controller.signal);
|
|
710
|
+
|
|
711
|
+
// Cancel from external controller
|
|
712
|
+
setTimeout(() => controller.abort(), 5000);
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
#### 3.3 Usage Monitoring
|
|
716
|
+
|
|
717
|
+
Track tokens, costs, and performance. Implementation in `/packages/zai/src/context.ts:175-196`.
|
|
718
|
+
|
|
719
|
+
```typescript
|
|
720
|
+
const result = await zai.extract(text, schema);
|
|
721
|
+
const usage = await result.usage();
|
|
722
|
+
|
|
723
|
+
console.log({
|
|
724
|
+
tokens: {
|
|
725
|
+
input: usage.tokens.input,
|
|
726
|
+
output: usage.tokens.output,
|
|
727
|
+
total: usage.tokens.total,
|
|
728
|
+
},
|
|
729
|
+
cost: {
|
|
730
|
+
input: usage.cost.input,
|
|
731
|
+
output: usage.cost.output,
|
|
732
|
+
total: usage.cost.total, // In USD
|
|
733
|
+
},
|
|
734
|
+
requests: usage.requests.requests,
|
|
735
|
+
cached: usage.requests.cached,
|
|
736
|
+
latency: usage.elapsedTime, // Milliseconds
|
|
737
|
+
});
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
#### 3.4 Method Chaining
|
|
741
|
+
|
|
742
|
+
Create specialized instances with different configurations:
|
|
743
|
+
|
|
744
|
+
```typescript
|
|
745
|
+
// Create temperature variant
|
|
746
|
+
const creativeZai = zai.with({ temperature: 0.9 });
|
|
747
|
+
|
|
748
|
+
// Chain multiple configurations
|
|
749
|
+
const preciseExtractor = zai
|
|
750
|
+
.with({ modelId: "gpt-4-turbo" })
|
|
751
|
+
.with({ temperature: 0.1 })
|
|
752
|
+
.learn("invoice-extraction");
|
|
753
|
+
|
|
754
|
+
const invoice = await preciseExtractor.extract(document, invoiceSchema);
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
#### 3.5 Abort Operations
|
|
758
|
+
|
|
759
|
+
Cancel long-running operations:
|
|
760
|
+
|
|
761
|
+
```typescript
|
|
762
|
+
const response = zai.summarize(massiveDocument);
|
|
763
|
+
|
|
764
|
+
// Abort after 5 seconds
|
|
765
|
+
setTimeout(() => response.abort(), 5000);
|
|
766
|
+
|
|
767
|
+
try {
|
|
768
|
+
const summary = await response;
|
|
769
|
+
} catch (error) {
|
|
770
|
+
if (error.name === "AbortError") {
|
|
771
|
+
console.log("Operation cancelled");
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
### 4. Error Handling
|
|
777
|
+
|
|
778
|
+
#### Common Error Types
|
|
779
|
+
|
|
780
|
+
```typescript
|
|
781
|
+
try {
|
|
782
|
+
const result = await zai.extract(text, schema);
|
|
783
|
+
} catch (error) {
|
|
784
|
+
if (error instanceof JsonParsingError) {
|
|
785
|
+
// Schema validation failed
|
|
786
|
+
console.error("Invalid JSON:", error.message);
|
|
787
|
+
} else if (error.name === "AbortError") {
|
|
788
|
+
// Operation was cancelled
|
|
789
|
+
console.log("Operation aborted");
|
|
790
|
+
} else if (error.code === "RATE_LIMIT") {
|
|
791
|
+
// API rate limit hit
|
|
792
|
+
await delay(error.retryAfter);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
#### Automatic Retries
|
|
798
|
+
|
|
799
|
+
ZAI includes built-in retry logic with exponential backoff. You can also wrap ZAI for custom retry behavior:
|
|
800
|
+
|
|
801
|
+
```typescript
|
|
802
|
+
// Example from /packages/llmz/examples/utils/zai.ts:3-33
|
|
803
|
+
import { withRetry } from "./utils/zai";
|
|
804
|
+
|
|
805
|
+
const reliableZai = withRetry(zai);
|
|
806
|
+
const result = await reliableZai.extract(text, schema); // Retries up to 10 times
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
### 5. Integration Patterns
|
|
810
|
+
|
|
811
|
+
#### 5.1 With Botpress Bots
|
|
812
|
+
|
|
813
|
+
```typescript
|
|
814
|
+
// In Botpress action or hook
|
|
815
|
+
import { Zai } from "@botpress/zai";
|
|
816
|
+
|
|
817
|
+
export const analyzeSentiment = async ({ client, input }) => {
|
|
818
|
+
const zai = new Zai({ client });
|
|
819
|
+
|
|
820
|
+
const sentiment = await zai.label(input.message, {
|
|
821
|
+
positive: "expresses positive sentiment",
|
|
822
|
+
negative: "expresses negative sentiment",
|
|
823
|
+
neutral: "is neutral in tone",
|
|
824
|
+
});
|
|
825
|
+
|
|
826
|
+
return { sentiment };
|
|
827
|
+
};
|
|
828
|
+
```
|
|
829
|
+
|
|
830
|
+
#### 5.2 With LLMz Framework
|
|
831
|
+
|
|
832
|
+
Example from `/packages/llmz/examples/07_chat_guardrails/index.ts:33-46`:
|
|
833
|
+
|
|
834
|
+
```typescript
|
|
835
|
+
import { execute, ThinkSignal } from "llmz";
|
|
836
|
+
import { Zai } from "@botpress/zai";
|
|
837
|
+
|
|
838
|
+
const zai = new Zai({ client });
|
|
839
|
+
|
|
840
|
+
// Use ZAI for content moderation
|
|
841
|
+
const guardrails = {
|
|
842
|
+
violence: "is free of violence",
|
|
843
|
+
hate: "is free of hate speech",
|
|
844
|
+
pii: "does not contain personal data",
|
|
845
|
+
};
|
|
846
|
+
|
|
847
|
+
await execute({
|
|
848
|
+
async onBeforeExecution(iteration) {
|
|
849
|
+
const checks = await zai.label(iteration.code, guardrails);
|
|
850
|
+
|
|
851
|
+
const violations = Object.entries(checks)
|
|
852
|
+
.filter(([_, result]) => !result.value)
|
|
853
|
+
.map(([rule, result]) => `${rule}: ${result.explanation}`);
|
|
854
|
+
|
|
855
|
+
if (violations.length > 0) {
|
|
856
|
+
throw new ThinkSignal(`Fix violations: ${violations.join(", ")}`);
|
|
857
|
+
}
|
|
858
|
+
},
|
|
859
|
+
});
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
#### 5.3 Batch Processing
|
|
863
|
+
|
|
864
|
+
```typescript
|
|
865
|
+
async function processBatch(documents: string[]) {
|
|
866
|
+
// Process in parallel with concurrency limit
|
|
867
|
+
const results = await Promise.all(
|
|
868
|
+
documents.map(async (doc, i) => {
|
|
869
|
+
// Stagger requests to avoid rate limits
|
|
870
|
+
await delay(i * 100);
|
|
871
|
+
|
|
872
|
+
return zai.extract(
|
|
873
|
+
doc,
|
|
874
|
+
z.object({
|
|
875
|
+
title: z.string(),
|
|
876
|
+
category: z.string(),
|
|
877
|
+
summary: z.string(),
|
|
878
|
+
}),
|
|
879
|
+
);
|
|
880
|
+
}),
|
|
881
|
+
);
|
|
882
|
+
|
|
883
|
+
return results;
|
|
884
|
+
}
|
|
885
|
+
```
|
|
886
|
+
|
|
887
|
+
## Part II: Stack Architecture
|
|
888
|
+
|
|
889
|
+
### 1. Core Architecture
|
|
890
|
+
|
|
891
|
+
#### 1.1 Package Structure
|
|
892
|
+
|
|
893
|
+
Located at `/packages/zai/`:
|
|
894
|
+
|
|
895
|
+
```
|
|
896
|
+
packages/zai/
|
|
897
|
+
├── src/
|
|
898
|
+
│ ├── index.ts # Main export
|
|
899
|
+
│ ├── zai.ts # Core Zai class (79-163)
|
|
900
|
+
│ ├── context.ts # Execution context management
|
|
901
|
+
│ ├── response.ts # Response wrapper with events
|
|
902
|
+
│ ├── emitter.ts # Event emitter implementation
|
|
903
|
+
│ ├── tokenizer.ts # Token counting utilities
|
|
904
|
+
│ ├── utils.ts # Helper functions
|
|
905
|
+
│ ├── operations/ # Operation implementations
|
|
906
|
+
│ │ ├── extract.ts # Data extraction (52-403)
|
|
907
|
+
│ │ ├── check.ts # Boolean checks
|
|
908
|
+
│ │ ├── label.ts # Multi-label classification
|
|
909
|
+
│ │ ├── rewrite.ts # Text transformation
|
|
910
|
+
│ │ ├── filter.ts # Array filtering
|
|
911
|
+
│ │ ├── text.ts # Text generation
|
|
912
|
+
│ │ ├── summarize.ts # Summarization
|
|
913
|
+
│ │ ├── constants.ts # Shared constants
|
|
914
|
+
│ │ └── errors.ts # Custom error types
|
|
915
|
+
│ └── adapters/ # Storage adapters
|
|
916
|
+
│ ├── adapter.ts # Base adapter interface
|
|
917
|
+
│ ├── botpress-table.ts # Botpress Tables adapter
|
|
918
|
+
│ └── memory.ts # In-memory adapter
|
|
919
|
+
├── e2e/ # End-to-end tests
|
|
920
|
+
├── build.ts # Build configuration
|
|
921
|
+
└── package.json # Dependencies
|
|
922
|
+
```
|
|
923
|
+
|
|
924
|
+
#### 1.2 Dependency Chain
|
|
925
|
+
|
|
926
|
+
```typescript
|
|
927
|
+
// Core dependencies (/packages/zai/package.json:34-39)
|
|
928
|
+
{
|
|
929
|
+
"@botpress/cognitive": "0.3.6", // LLM abstraction layer
|
|
930
|
+
"@bpinternal/zui": "^1.3.2", // Zod-based schema library
|
|
931
|
+
"@bpinternal/thicktoken": "^1.0.0", // WASM tokenizer
|
|
932
|
+
"json5": "^2.2.3", // Flexible JSON parsing
|
|
933
|
+
"jsonrepair": "^3.10.0", // Fix malformed JSON
|
|
934
|
+
"lodash-es": "^4.17.21" // Utility functions
|
|
935
|
+
}
|
|
936
|
+
```
|
|
937
|
+
|
|
938
|
+
#### 1.3 Class Hierarchy
|
|
939
|
+
|
|
940
|
+
**Main Class** (`/packages/zai/src/zai.ts:79-163`):
|
|
941
|
+
|
|
942
|
+
```typescript
|
|
943
|
+
export class Zai {
|
|
944
|
+
protected client: Cognitive; // LLM client
|
|
945
|
+
protected Model: ModelId; // Selected model
|
|
946
|
+
protected namespace: string; // Operation namespace
|
|
947
|
+
protected adapter: Adapter; // Storage adapter
|
|
948
|
+
protected activeLearning: ActiveLearning;
|
|
949
|
+
|
|
950
|
+
constructor(config: ZaiConfig);
|
|
951
|
+
with(options: Partial<ZaiConfig>): Zai;
|
|
952
|
+
learn(taskId: string): Zai;
|
|
953
|
+
}
|
|
954
|
+
```
|
|
955
|
+
|
|
956
|
+
**Context Management** (`/packages/zai/src/context.ts:45-197`):
|
|
957
|
+
|
|
958
|
+
```typescript
|
|
959
|
+
export class ZaiContext {
|
|
960
|
+
private _client: Cognitive;
|
|
961
|
+
public controller: AbortController;
|
|
962
|
+
|
|
963
|
+
async generateContent<Out>(props): Promise<{ meta; output; text; extracted }>;
|
|
964
|
+
get usage(): Usage;
|
|
965
|
+
on<K>(type: K, listener: Function): this;
|
|
966
|
+
}
|
|
967
|
+
```
|
|
968
|
+
|
|
969
|
+
### 2. Execution Pipeline
|
|
970
|
+
|
|
971
|
+
#### 2.1 Operation Flow
|
|
972
|
+
|
|
973
|
+
1. **User calls operation** (e.g., `zai.extract()`)
|
|
974
|
+
2. **Create ZaiContext** with client, model, and task info
|
|
975
|
+
3. **Prepare prompt** using operation-specific template
|
|
976
|
+
4. **Check active learning** for cached examples
|
|
977
|
+
5. **Generate content** via Cognitive API
|
|
978
|
+
6. **Transform response** based on operation type
|
|
979
|
+
7. **Store example** if active learning enabled
|
|
980
|
+
8. **Return Response** wrapper with result
|
|
981
|
+
|
|
982
|
+
#### 2.2 Prompt Engineering
|
|
983
|
+
|
|
984
|
+
Each operation uses sophisticated prompts. Example from extract (`/packages/zai/src/operations/extract.ts:301-316`):
|
|
985
|
+
|
|
986
|
+
```typescript
|
|
987
|
+
systemPrompt: `
|
|
988
|
+
Extract the following information from the input:
|
|
989
|
+
${schemaTypescript}
|
|
990
|
+
====
|
|
991
|
+
${instructions.map((x) => `• ${x}`).join("\n")}
|
|
992
|
+
`.trim();
|
|
993
|
+
```
|
|
994
|
+
|
|
995
|
+
Operations include:
|
|
996
|
+
|
|
997
|
+
- Schema definitions in TypeScript format
|
|
998
|
+
- Clear instructions with examples
|
|
999
|
+
- Special markers for parsing (e.g., `■json_start■`, `■json_end■`)
|
|
1000
|
+
|
|
1001
|
+
#### 2.3 Chunking Strategy
|
|
1002
|
+
|
|
1003
|
+
For large documents (`/packages/zai/src/operations/extract.ts:112-149`):
|
|
1004
|
+
|
|
1005
|
+
```typescript
|
|
1006
|
+
if (tokenizer.count(inputAsString) > options.chunkLength) {
|
|
1007
|
+
// 1. Split into chunks
|
|
1008
|
+
const tokens = tokenizer.split(inputAsString);
|
|
1009
|
+
const chunks = chunk(tokens, options.chunkLength);
|
|
1010
|
+
|
|
1011
|
+
// 2. Process in parallel
|
|
1012
|
+
const all = await Promise.allSettled(
|
|
1013
|
+
chunks.map((chunk) => extract(chunk, schema, options, ctx)),
|
|
1014
|
+
);
|
|
1015
|
+
|
|
1016
|
+
// 3. Merge results recursively
|
|
1017
|
+
return extract(mergePrompt, originalSchema, options, ctx);
|
|
1018
|
+
}
|
|
1019
|
+
```
|
|
1020
|
+
|
|
1021
|
+
### 3. Storage & Learning
|
|
1022
|
+
|
|
1023
|
+
#### 3.1 Adapter System
|
|
1024
|
+
|
|
1025
|
+
**Base Interface** (`/packages/zai/src/adapters/adapter.ts`):
|
|
1026
|
+
|
|
1027
|
+
```typescript
|
|
1028
|
+
export interface Adapter {
|
|
1029
|
+
saveExample(example: Example): Promise<void>;
|
|
1030
|
+
getExamples<I, O>(params: GetExamplesParams): Promise<Example<I, O>[]>;
|
|
1031
|
+
}
|
|
1032
|
+
```
|
|
1033
|
+
|
|
1034
|
+
**Implementations:**
|
|
1035
|
+
|
|
1036
|
+
**MemoryAdapter** (`/packages/zai/src/adapters/memory.ts`):
|
|
1037
|
+
|
|
1038
|
+
- In-memory storage, no persistence
|
|
1039
|
+
- Returns all stored examples (no filtering)
|
|
1040
|
+
- Useful for testing and development
|
|
1041
|
+
- No status management or approval workflow
|
|
1042
|
+
|
|
1043
|
+
**TableAdapter** (`/packages/zai/src/adapters/botpress-table.ts:82-231`):
|
|
1044
|
+
|
|
1045
|
+
- Persistent storage via Botpress Tables
|
|
1046
|
+
- Filters by status, taskType, and taskId
|
|
1047
|
+
- Performs similarity search on input field (first 1024 chars)
|
|
1048
|
+
- Auto-creates table with schema on first use
|
|
1049
|
+
- Table configuration:
|
|
1050
|
+
- Factor: 30 (affects table performance)
|
|
1051
|
+
- Frozen: true (schema cannot be modified)
|
|
1052
|
+
- Searchable: input field only
|
|
1053
|
+
- Tags: `'x-studio-readonly': 'true'` (read-only in Studio)
|
|
1054
|
+
|
|
1055
|
+
#### 3.2 Active Learning Flow
|
|
1056
|
+
|
|
1057
|
+
When enabled (`/packages/zai/src/operations/extract.ts:362-383`):
|
|
1058
|
+
|
|
1059
|
+
```typescript
|
|
1060
|
+
if (taskId && ctx.adapter && !ctx.controller.signal.aborted) {
|
|
1061
|
+
await ctx.adapter.saveExample({
|
|
1062
|
+
key: fastHash(JSON.stringify({ taskType, taskId, input, instructions })),
|
|
1063
|
+
taskId: `zai/${taskId}`,
|
|
1064
|
+
taskType,
|
|
1065
|
+
instructions,
|
|
1066
|
+
input: inputAsString,
|
|
1067
|
+
output: final,
|
|
1068
|
+
metadata: { cost, latency, model, tokens },
|
|
1069
|
+
status: "pending", // Default - requires approval
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
```
|
|
1073
|
+
|
|
1074
|
+
**Retrieval Process** (`/packages/zai/src/adapters/botpress-table.ts:96-124`):
|
|
1075
|
+
|
|
1076
|
+
```typescript
|
|
1077
|
+
const { rows } = await this._client.findTableRows({
|
|
1078
|
+
table: this._tableName,
|
|
1079
|
+
search: JSON.stringify({ value: input }).substring(0, 1023),
|
|
1080
|
+
limit: 10,
|
|
1081
|
+
filter: {
|
|
1082
|
+
taskType,
|
|
1083
|
+
taskId,
|
|
1084
|
+
status: "approved", // Only approved examples used!
|
|
1085
|
+
},
|
|
1086
|
+
});
|
|
1087
|
+
```
|
|
1088
|
+
|
|
1089
|
+
#### 3.3 Example Matching
|
|
1090
|
+
|
|
1091
|
+
Examples are retrieved and ranked by relevance:
|
|
1092
|
+
|
|
1093
|
+
1. **Exact key match**: Hash comparison, returns immediately without LLM call
|
|
1094
|
+
2. **Similarity search**: Botpress Tables API handles similarity (likely embeddings)
|
|
1095
|
+
3. **Token budget allocation**: Examples included up to token limit
|
|
1096
|
+
4. **Prompt inclusion**: Up to 10 examples guide the LLM
|
|
1097
|
+
|
|
1098
|
+
### 4. Performance Optimization
|
|
1099
|
+
|
|
1100
|
+
#### 4.1 Token Management
|
|
1101
|
+
|
|
1102
|
+
**Tokenizer Integration** (`/packages/zai/src/zai.ts:125-134`):
|
|
1103
|
+
|
|
1104
|
+
```typescript
|
|
1105
|
+
protected async getTokenizer() {
|
|
1106
|
+
Zai.tokenizer ??= await (async () => {
|
|
1107
|
+
while (!getWasmTokenizer) {
|
|
1108
|
+
await new Promise(resolve => setTimeout(resolve, 25))
|
|
1109
|
+
}
|
|
1110
|
+
return getWasmTokenizer() as TextTokenizer
|
|
1111
|
+
})()
|
|
1112
|
+
return Zai.tokenizer
|
|
1113
|
+
}
|
|
1114
|
+
```
|
|
1115
|
+
|
|
1116
|
+
**Budget Allocation**:
|
|
1117
|
+
|
|
1118
|
+
- Input: 50% of available tokens
|
|
1119
|
+
- Condition/Instructions: 20%
|
|
1120
|
+
- Examples: 30%
|
|
1121
|
+
|
|
1122
|
+
#### 4.2 Parallel Processing
|
|
1123
|
+
|
|
1124
|
+
Operations process chunks in parallel:
|
|
1125
|
+
|
|
1126
|
+
- Automatic detection of large inputs
|
|
1127
|
+
- Concurrent chunk processing
|
|
1128
|
+
- Result aggregation and merging
|
|
1129
|
+
|
|
1130
|
+
#### 4.3 Caching Strategy
|
|
1131
|
+
|
|
1132
|
+
1. **Model Details Cache**: Model capabilities cached per session
|
|
1133
|
+
2. **Tokenizer Cache**: Single WASM instance shared
|
|
1134
|
+
3. **Example Cache**: Active learning examples stored and reused
|
|
1135
|
+
4. **Response Cache**: Cognitive layer handles HTTP caching
|
|
1136
|
+
|
|
1137
|
+
### 5. Error Recovery
|
|
1138
|
+
|
|
1139
|
+
#### 5.1 Retry Mechanism
|
|
1140
|
+
|
|
1141
|
+
Built into context generation (`/packages/zai/src/context.ts:117-169`):
|
|
1142
|
+
|
|
1143
|
+
```typescript
|
|
1144
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
1145
|
+
try {
|
|
1146
|
+
const response = await this._client.generateContent({...})
|
|
1147
|
+
return { meta, output, text, extracted }
|
|
1148
|
+
} catch (error) {
|
|
1149
|
+
if (attempt === maxRetries) throw error
|
|
1150
|
+
|
|
1151
|
+
messages.push({
|
|
1152
|
+
role: 'user',
|
|
1153
|
+
content: `ERROR: ${error.message}. Please fix and retry.`
|
|
1154
|
+
})
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
```
|
|
1158
|
+
|
|
1159
|
+
#### 5.2 JSON Repair
|
|
1160
|
+
|
|
1161
|
+
For extract operations (`/packages/zai/src/operations/extract.ts:323-339`):
|
|
1162
|
+
|
|
1163
|
+
```typescript
|
|
1164
|
+
try {
|
|
1165
|
+
const json = x.slice(0, x.indexOf(END)).trim();
|
|
1166
|
+
const repairedJson = jsonrepair(json); // Fix common JSON errors
|
|
1167
|
+
const parsedJson = JSON5.parse(repairedJson); // Flexible parsing
|
|
1168
|
+
const safe = schema.safeParse(parsedJson); // Validate
|
|
1169
|
+
|
|
1170
|
+
if (safe.success) return safe.data;
|
|
1171
|
+
if (options.strict) throw new JsonParsingError(x, safe.error);
|
|
1172
|
+
return parsedJson; // Non-strict mode
|
|
1173
|
+
} catch (error) {
|
|
1174
|
+
throw new JsonParsingError(x, error);
|
|
1175
|
+
}
|
|
1176
|
+
```
|
|
1177
|
+
|
|
1178
|
+
### 6. Model Management
|
|
1179
|
+
|
|
1180
|
+
#### 6.1 Model Selection
|
|
1181
|
+
|
|
1182
|
+
Models configured at initialization (`/packages/zai/src/zai.ts:50-68`):
|
|
1183
|
+
|
|
1184
|
+
```typescript
|
|
1185
|
+
modelId: z.custom<ModelId | string>((value) => {
|
|
1186
|
+
if (typeof value !== "string") return false;
|
|
1187
|
+
if (value !== "best" && value !== "fast" && !value.includes(":")) {
|
|
1188
|
+
return false;
|
|
1189
|
+
}
|
|
1190
|
+
return true;
|
|
1191
|
+
}).default("best");
|
|
1192
|
+
```
|
|
1193
|
+
|
|
1194
|
+
Options:
|
|
1195
|
+
|
|
1196
|
+
- `'best'`: Highest quality model
|
|
1197
|
+
- `'fast'`: Lower latency model
|
|
1198
|
+
- Custom model IDs: `'openai:gpt-4-turbo'`
|
|
1199
|
+
|
|
1200
|
+
#### 6.2 Model Capabilities
|
|
1201
|
+
|
|
1202
|
+
Retrieved dynamically (`/packages/zai/src/zai.ts:136-140`):
|
|
1203
|
+
|
|
1204
|
+
```typescript
|
|
1205
|
+
protected async fetchModelDetails(): Promise<void> {
|
|
1206
|
+
if (!this.ModelDetails) {
|
|
1207
|
+
this.ModelDetails = await this.client.getModelDetails(this.Model)
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
```
|
|
1211
|
+
|
|
1212
|
+
Used for:
|
|
1213
|
+
|
|
1214
|
+
- Token limits
|
|
1215
|
+
- Cost calculation
|
|
1216
|
+
- Feature availability
|
|
1217
|
+
|
|
1218
|
+
## Part III: Troubleshooting
|
|
1219
|
+
|
|
1220
|
+
### Common Issues
|
|
1221
|
+
|
|
1222
|
+
#### 1. Token Limit Exceeded
|
|
1223
|
+
|
|
1224
|
+
**Problem**: Input too large for model
|
|
1225
|
+
**Solution**: Adjust `chunkLength` parameter
|
|
1226
|
+
|
|
1227
|
+
```typescript
|
|
1228
|
+
const result = await zai.extract(hugeDocument, schema, {
|
|
1229
|
+
chunkLength: 4000, // Smaller chunks
|
|
1230
|
+
});
|
|
1231
|
+
```
|
|
1232
|
+
|
|
1233
|
+
#### 2. Schema Validation Failures
|
|
1234
|
+
|
|
1235
|
+
**Problem**: Extracted data doesn't match schema
|
|
1236
|
+
**Solution**: Use non-strict mode or improve instructions
|
|
1237
|
+
|
|
1238
|
+
```typescript
|
|
1239
|
+
const result = await zai.extract(input, schema, {
|
|
1240
|
+
strict: false, // Allow partial matches
|
|
1241
|
+
instructions: "If age is missing, use -1",
|
|
1242
|
+
});
|
|
1243
|
+
```
|
|
1244
|
+
|
|
1245
|
+
#### 3. Rate Limiting
|
|
1246
|
+
|
|
1247
|
+
**Problem**: Too many requests
|
|
1248
|
+
**Solution**: Implement backoff or reduce concurrency
|
|
1249
|
+
|
|
1250
|
+
```typescript
|
|
1251
|
+
// Stagger requests
|
|
1252
|
+
for (const [i, doc] of documents.entries()) {
|
|
1253
|
+
await delay(i * 200); // 200ms between requests
|
|
1254
|
+
await zai.summarize(doc);
|
|
1255
|
+
}
|
|
1256
|
+
```
|
|
1257
|
+
|
|
1258
|
+
#### 4. Memory Issues with Large Documents
|
|
1259
|
+
|
|
1260
|
+
**Problem**: Out of memory with huge inputs
|
|
1261
|
+
**Solution**: Process in streaming fashion
|
|
1262
|
+
|
|
1263
|
+
```typescript
|
|
1264
|
+
// Split manually before processing
|
|
1265
|
+
const chunks = splitIntoChunks(document, 10000);
|
|
1266
|
+
const summaries = await Promise.all(
|
|
1267
|
+
chunks.map((chunk) => zai.summarize(chunk)),
|
|
1268
|
+
);
|
|
1269
|
+
const final = await zai.summarize(summaries.join("\n"));
|
|
1270
|
+
```
|
|
1271
|
+
|
|
1272
|
+
### Performance Tuning
|
|
1273
|
+
|
|
1274
|
+
#### 1. Model Selection
|
|
1275
|
+
|
|
1276
|
+
- Use `'fast'` model for high-volume, low-complexity tasks
|
|
1277
|
+
- Use `'best'` model for complex extraction or generation
|
|
1278
|
+
- Specify exact model for consistency
|
|
1279
|
+
|
|
1280
|
+
#### 2. Chunk Size Optimization
|
|
1281
|
+
|
|
1282
|
+
- Smaller chunks (2-4k tokens): More parallel processing, potentially less context
|
|
1283
|
+
- Larger chunks (8-16k tokens): Better context preservation, less parallelism
|
|
1284
|
+
- Default (16k): Good balance for most use cases
|
|
1285
|
+
|
|
1286
|
+
#### 3. Active Learning
|
|
1287
|
+
|
|
1288
|
+
Enable for repetitive tasks:
|
|
1289
|
+
|
|
1290
|
+
```typescript
|
|
1291
|
+
const zai = new Zai({
|
|
1292
|
+
client,
|
|
1293
|
+
activeLearning: {
|
|
1294
|
+
enable: true,
|
|
1295
|
+
tableName: "ProductExtractionTable",
|
|
1296
|
+
taskId: "product-catalog",
|
|
1297
|
+
},
|
|
1298
|
+
});
|
|
1299
|
+
```
|
|
1300
|
+
|
|
1301
|
+
Benefits:
|
|
1302
|
+
|
|
1303
|
+
- Reduced latency (cached exact matches)
|
|
1304
|
+
- Improved accuracy (learns from examples)
|
|
1305
|
+
- Lower costs (fewer API calls)
|
|
1306
|
+
|
|
1307
|
+
## Quick Reference
|
|
1308
|
+
|
|
1309
|
+
### Essential Methods
|
|
1310
|
+
|
|
1311
|
+
| Method | Purpose | Example |
|
|
1312
|
+
| ------------- | ---------------------- | ------------------------------------ |
|
|
1313
|
+
| `extract()` | Get structured data | `zai.extract(text, schema)` |
|
|
1314
|
+
| `check()` | Verify conditions | `zai.check(text, 'is positive')` |
|
|
1315
|
+
| `label()` | Multi-classification | `zai.label(text, criteria)` |
|
|
1316
|
+
| `rewrite()` | Transform text | `zai.rewrite(text, 'translate')` |
|
|
1317
|
+
| `filter()` | Filter arrays | `zai.filter(items, condition)` |
|
|
1318
|
+
| `text()` | Generate content | `zai.text(prompt, options)` |
|
|
1319
|
+
| `summarize()` | Create summaries | `zai.summarize(document)` |
|
|
1320
|
+
| `answer()` | Answer with citations | `zai.answer(docs, question)` |
|
|
1321
|
+
| `rate()` | Rate array items (1-5) | `zai.rate(items, criteria)` |
|
|
1322
|
+
| `sort()` | Sort with natural lang | `zai.sort(items, instructions)` |
|
|
1323
|
+
| `group()` | Group array elements | `zai.group(items, { instructions })` |
|
|
1324
|
+
| `patch()` | Patch files with AI | `zai.patch(files, instructions)` |
|
|
1325
|
+
|
|
1326
|
+
### Configuration Options
|
|
1327
|
+
|
|
1328
|
+
| Option | Default | Description |
|
|
1329
|
+
| -------------------------- | ----------------------- | ------------------- |
|
|
1330
|
+
| `modelId` | `'best'` | Model selection |
|
|
1331
|
+
| `namespace` | `'zai'` | Operation namespace |
|
|
1332
|
+
| `activeLearning.enable` | `false` | Enable learning |
|
|
1333
|
+
| `activeLearning.tableName` | `'ActiveLearningTable'` | Storage table |
|
|
1334
|
+
| `activeLearning.taskId` | `'default'` | Task identifier |
|
|
1335
|
+
|
|
1336
|
+
### Token Limits
|
|
1337
|
+
|
|
1338
|
+
| Model Type | Input Tokens | Recommended Chunk Size |
|
|
1339
|
+
| ---------- | ------------ | ---------------------- |
|
|
1340
|
+
| Fast | 8k | 4000 |
|
|
1341
|
+
| Best | 128k | 16000 |
|
|
1342
|
+
| Custom | Varies | Model-specific |
|
|
1343
|
+
|
|
1344
|
+
### Response Methods
|
|
1345
|
+
|
|
1346
|
+
| Method | Returns | Usage |
|
|
1347
|
+
| ----------------------------- | --------------- | ---------------------- |
|
|
1348
|
+
| `await response` | Simple result | Quick access to result |
|
|
1349
|
+
| `await response.full()` | Detailed result | Includes explanations |
|
|
1350
|
+
| `await response.usage()` | Usage stats | Tokens, cost, latency |
|
|
1351
|
+
| `response.on('progress', fn)` | Event listener | Track progress |
|
|
1352
|
+
| `response.abort()` | void | Cancel operation |
|
|
1353
|
+
|
|
1354
|
+
### Error Types
|
|
1355
|
+
|
|
1356
|
+
| Error | Cause | Solution |
|
|
1357
|
+
| ------------------ | ------------------- | ---------------------------- |
|
|
1358
|
+
| `JsonParsingError` | Invalid JSON/schema | Check schema, use non-strict |
|
|
1359
|
+
| `AbortError` | Operation cancelled | Handle cancellation |
|
|
1360
|
+
| `Rate limit` | Too many requests | Implement backoff |
|
|
1361
|
+
| `Token limit` | Input too large | Reduce chunk size |
|
|
1362
|
+
|
|
1363
|
+
### Active Learning States
|
|
1364
|
+
|
|
1365
|
+
| Status | Used for Learning | Description |
|
|
1366
|
+
| ------------ | ----------------- | ---------------------------------- |
|
|
1367
|
+
| `'pending'` | ❌ No | Default status for new examples |
|
|
1368
|
+
| `'approved'` | ✅ Yes | Manually approved, used in prompts |
|
|
1369
|
+
| `'rejected'` | ❌ No | Manually rejected, ignored |
|
|
1370
|
+
|
|
1371
|
+
### Active Learning Flow
|
|
1372
|
+
|
|
1373
|
+
1. Generate hash key from input → Check exact match
|
|
1374
|
+
2. If match found → Return cached result (skip LLM)
|
|
1375
|
+
3. If no match → Search similar examples (max 10)
|
|
1376
|
+
4. Include examples in prompt → Call LLM
|
|
1377
|
+
5. Save result with `status: 'pending'`
|
|
1378
|
+
6. Result needs external approval to be used in future
|
|
1379
|
+
|
|
1380
|
+
### Active Learning Configuration
|
|
1381
|
+
|
|
1382
|
+
| Setting | Required | Description |
|
|
1383
|
+
| ----------- | -------- | ------------------------------- |
|
|
1384
|
+
| `enable` | Yes | Set to `true` to activate |
|
|
1385
|
+
| `tableName` | Yes | Must end with "Table" |
|
|
1386
|
+
| `taskId` | Yes | Unique identifier for task type |
|
|
1387
|
+
|
|
1388
|
+
**Example Configuration:**
|
|
1389
|
+
|
|
1390
|
+
```typescript
|
|
1391
|
+
{
|
|
1392
|
+
enable: true,
|
|
1393
|
+
tableName: 'SpamDetectionTable', // Must end with "Table"
|
|
1394
|
+
taskId: 'email-spam' // Becomes 'zai/email-spam'
|
|
1395
|
+
}
|
|
1396
|
+
```
|
|
1397
|
+
|
|
1398
|
+
## Summary
|
|
1399
|
+
|
|
1400
|
+
ZAI provides a production-ready, type-safe interface for AI operations with:
|
|
1401
|
+
|
|
1402
|
+
- **12 core operations** covering extraction, verification, generation, transformation, analysis, and code patching
|
|
1403
|
+
- **Automatic handling** of documents of any size through intelligent chunking
|
|
1404
|
+
- **Active learning** that improves accuracy over time
|
|
1405
|
+
- **Full observability** with progress tracking and usage monitoring
|
|
1406
|
+
- **Battle-tested** in production at Botpress, powering millions of AI interactions
|
|
1407
|
+
|
|
1408
|
+
The library abstracts complexity while maintaining flexibility, making it ideal for both simple prototypes and production systems requiring scale, reliability, and cost optimization.
|