@botpress/zai 2.4.1 → 2.5.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.
@@ -41,7 +41,73 @@ type AnyObjectOrArray = Record<string, unknown> | Array<unknown>
41
41
 
42
42
  declare module '@botpress/zai' {
43
43
  interface Zai {
44
- /** Extracts one or many elements from an arbitrary input */
44
+ /**
45
+ * Extracts structured data from unstructured text using a Zod schema.
46
+ *
47
+ * This operation uses LLMs to intelligently parse text and extract information
48
+ * according to your schema. It handles large inputs automatically by chunking
49
+ * and supports both objects and arrays.
50
+ *
51
+ * @param input - The text or data to extract information from
52
+ * @param schema - Zod schema defining the structure to extract
53
+ * @param options - Optional configuration for extraction behavior
54
+ * @returns A Response promise that resolves to data matching your schema
55
+ *
56
+ * @example Extract a single object
57
+ * ```typescript
58
+ * import { z } from '@bpinternal/zui'
59
+ *
60
+ * const personSchema = z.object({
61
+ * name: z.string(),
62
+ * age: z.number(),
63
+ * email: z.string().email()
64
+ * })
65
+ *
66
+ * const text = "Contact John Doe (35) at john@example.com"
67
+ * const person = await zai.extract(text, personSchema)
68
+ * // Result: { name: 'John Doe', age: 35, email: 'john@example.com' }
69
+ * ```
70
+ *
71
+ * @example Extract an array of items
72
+ * ```typescript
73
+ * const productSchema = z.array(z.object({
74
+ * name: z.string(),
75
+ * price: z.number()
76
+ * }))
77
+ *
78
+ * const text = "We have Apple ($1.50), Banana ($0.80), and Orange ($1.20)"
79
+ * const products = await zai.extract(text, productSchema)
80
+ * // Result: [
81
+ * // { name: 'Apple', price: 1.50 },
82
+ * // { name: 'Banana', price: 0.80 },
83
+ * // { name: 'Orange', price: 1.20 }
84
+ * // ]
85
+ * ```
86
+ *
87
+ * @example With custom instructions
88
+ * ```typescript
89
+ * const result = await zai.extract(document, schema, {
90
+ * instructions: 'Only extract confirmed information, skip uncertain data',
91
+ * chunkLength: 10000, // Smaller chunks for better accuracy
92
+ * strict: true // Enforce strict schema validation
93
+ * })
94
+ * ```
95
+ *
96
+ * @example Track usage and cost
97
+ * ```typescript
98
+ * const response = zai.extract(text, schema)
99
+ *
100
+ * // Monitor progress
101
+ * response.on('progress', (usage) => {
102
+ * console.log(`Tokens used: ${usage.tokens.total}`)
103
+ * console.log(`Cost so far: $${usage.cost.total}`)
104
+ * })
105
+ *
106
+ * // Get full results
107
+ * const { output, usage, elapsed } = await response.result()
108
+ * console.log(`Extraction took ${elapsed}ms and cost $${usage.cost.total}`)
109
+ * ```
110
+ */
45
111
  extract<S extends OfType<any>>(input: unknown, schema: S, options?: Options): Response<S['_output']>
46
112
  }
47
113
  }
@@ -42,7 +42,92 @@ const _Options = z.object({
42
42
 
43
43
  declare module '@botpress/zai' {
44
44
  interface Zai {
45
- /** Filters elements of an array against a condition */
45
+ /**
46
+ * Filters array elements based on a natural language condition.
47
+ *
48
+ * This operation evaluates each element against a condition using LLMs,
49
+ * returning only elements that match. Handles large arrays automatically
50
+ * by processing in parallel chunks.
51
+ *
52
+ * @param input - Array of elements to filter
53
+ * @param condition - Natural language description of what to keep
54
+ * @param options - Configuration for token limits per item and examples
55
+ * @returns Response promise resolving to filtered array
56
+ *
57
+ * @example Filter positive reviews
58
+ * ```typescript
59
+ * const reviews = [
60
+ * "Great product, love it!",
61
+ * "Terrible quality, broke immediately",
62
+ * "Amazing! Exceeded expectations",
63
+ * "Worst purchase ever"
64
+ * ]
65
+ *
66
+ * const positive = await zai.filter(reviews, 'Keep only positive reviews')
67
+ * // Result: ["Great product, love it!", "Amazing! Exceeded expectations"]
68
+ * ```
69
+ *
70
+ * @example Filter technical questions
71
+ * ```typescript
72
+ * const questions = [
73
+ * "How do I deploy to production?",
74
+ * "What time is lunch?",
75
+ * "Why is the API returning 500 errors?",
76
+ * "Can you book the conference room?"
77
+ * ]
78
+ *
79
+ * const technical = await zai.filter(
80
+ * questions,
81
+ * 'Keep only technical or engineering questions'
82
+ * )
83
+ * // Result: ["How do I deploy to production?", "Why is the API returning 500 errors?"]
84
+ * ```
85
+ *
86
+ * @example Filter with object array
87
+ * ```typescript
88
+ * const products = [
89
+ * { name: 'Laptop', category: 'Electronics', inStock: true },
90
+ * { name: 'Desk', category: 'Furniture', inStock: false },
91
+ * { name: 'Mouse', category: 'Electronics', inStock: true },
92
+ * { name: 'Chair', category: 'Furniture', inStock: true }
93
+ * ]
94
+ *
95
+ * const available = await zai.filter(
96
+ * products,
97
+ * 'Keep only products that are in stock'
98
+ * )
99
+ * // Returns products where inStock === true
100
+ * ```
101
+ *
102
+ * @example Complex filtering logic
103
+ * ```typescript
104
+ * const emails = [...] // Array of email objects
105
+ *
106
+ * const urgent = await zai.filter(
107
+ * emails,
108
+ * 'Keep emails that are urgent, from the CEO, or mention "critical bug"'
109
+ * )
110
+ * ```
111
+ *
112
+ * @example With examples for consistency
113
+ * ```typescript
114
+ * const filtered = await zai.filter(items, 'Keep valid entries', {
115
+ * examples: [
116
+ * {
117
+ * input: { status: 'active', verified: true },
118
+ * filter: true,
119
+ * reason: 'Active and verified'
120
+ * },
121
+ * {
122
+ * input: { status: 'pending', verified: false },
123
+ * filter: false,
124
+ * reason: 'Not yet verified'
125
+ * }
126
+ * ],
127
+ * tokensPerItem: 100 // Limit tokens per item for performance
128
+ * })
129
+ * ```
130
+ */
46
131
  filter<T>(input: Array<T>, condition: string, options?: Options): Response<Array<T>>
47
132
  }
48
133
  }
@@ -43,6 +43,156 @@ const _Options = z.object({
43
43
 
44
44
  declare module '@botpress/zai' {
45
45
  interface Zai {
46
+ /**
47
+ * Groups array items into categories based on semantic similarity or criteria.
48
+ *
49
+ * This operation intelligently categorizes items by analyzing their content and
50
+ * creating meaningful groups. It can discover natural groupings automatically or
51
+ * use predefined categories. Perfect for clustering, classification, and organization.
52
+ *
53
+ * @param input - Array of items to group
54
+ * @param options - Configuration for grouping behavior, instructions, and initial categories
55
+ * @returns Response with groups array (simplified to Record<groupLabel, items[]>)
56
+ *
57
+ * @example Automatic grouping
58
+ * ```typescript
59
+ * const messages = [
60
+ * "I can't log in to my account",
61
+ * "How do I reset my password?",
62
+ * "When will my order arrive?",
63
+ * "The app keeps crashing",
64
+ * "I haven't received my package",
65
+ * "Error 500 on checkout"
66
+ * ]
67
+ *
68
+ * const groups = await zai.group(messages, {
69
+ * instructions: 'Group by type of customer issue'
70
+ * })
71
+ * // Result (simplified):
72
+ * // {
73
+ * // "Login Issues": ["I can't log in...", "How do I reset..."],
74
+ * // "Shipping Questions": ["When will my order...", "I haven't received..."],
75
+ * // "Technical Errors": ["The app keeps crashing", "Error 500..."]
76
+ * // }
77
+ *
78
+ * // Full result:
79
+ * const { output } = await zai.group(messages, { instructions: '...' }).result()
80
+ * // output: [
81
+ * // { id: 'login_issues', label: 'Login Issues', elements: [...] },
82
+ * // { id: 'shipping', label: 'Shipping Questions', elements: [...] },
83
+ * // { id: 'errors', label: 'Technical Errors', elements: [...] }
84
+ * // ]
85
+ * ```
86
+ *
87
+ * @example With predefined categories
88
+ * ```typescript
89
+ * const articles = [
90
+ * "How to build a React app",
91
+ * "Python machine learning tutorial",
92
+ * "Understanding Docker containers",
93
+ * "Vue.js best practices",
94
+ * "Deep learning with TensorFlow"
95
+ * ]
96
+ *
97
+ * const groups = await zai.group(articles, {
98
+ * instructions: 'Categorize by technology',
99
+ * initialGroups: [
100
+ * { id: 'frontend', label: 'Frontend Development' },
101
+ * { id: 'backend', label: 'Backend Development' },
102
+ * { id: 'ml', label: 'Machine Learning' },
103
+ * { id: 'devops', label: 'DevOps & Infrastructure' }
104
+ * ]
105
+ * })
106
+ * // Groups articles into predefined categories
107
+ * ```
108
+ *
109
+ * @example Grouping products
110
+ * ```typescript
111
+ * const products = [
112
+ * { name: 'Laptop', price: 999, category: 'Electronics' },
113
+ * { name: 'Desk', price: 299, category: 'Furniture' },
114
+ * { name: 'Mouse', price: 29, category: 'Electronics' },
115
+ * { name: 'Chair', price: 199, category: 'Furniture' }
116
+ * ]
117
+ *
118
+ * const grouped = await zai.group(products, {
119
+ * instructions: 'Group by price range: budget (< $100), mid-range ($100-$500), premium (> $500)'
120
+ * })
121
+ * // Result:
122
+ * // {
123
+ * // "Budget": [Mouse],
124
+ * // "Mid-range": [Chair, Desk],
125
+ * // "Premium": [Laptop]
126
+ * // }
127
+ * ```
128
+ *
129
+ * @example Content categorization
130
+ * ```typescript
131
+ * const emails = [
132
+ * { subject: 'Meeting tomorrow', body: '...', from: 'boss@company.com' },
133
+ * { subject: 'Invoice #1234', body: '...', from: 'billing@vendor.com' },
134
+ * { subject: 'Weekly report', body: '...', from: 'team@company.com' },
135
+ * { subject: 'Payment received', body: '...', from: 'accounting@company.com' }
136
+ * ]
137
+ *
138
+ * const categorized = await zai.group(emails, {
139
+ * instructions: 'Categorize by email type: work communication, financial, reports',
140
+ * tokensPerElement: 300 // Allow more context per email
141
+ * })
142
+ * ```
143
+ *
144
+ * @example Customer feedback grouping
145
+ * ```typescript
146
+ * const feedback = [
147
+ * "Love the new UI!",
148
+ * "App is too slow",
149
+ * "Great customer service",
150
+ * "Confusing navigation",
151
+ * "Fast shipping!",
152
+ * "Hard to find features"
153
+ * ]
154
+ *
155
+ * const grouped = await zai.group(feedback, {
156
+ * instructions: 'Group by aspect: UI/UX, Performance, Customer Service, Shipping'
157
+ * })
158
+ * ```
159
+ *
160
+ * @example Topic clustering for research
161
+ * ```typescript
162
+ * const papers = [
163
+ * { title: 'Transformer Networks for NLP', abstract: '...' },
164
+ * { title: 'CNN Image Classification', abstract: '...' },
165
+ * { title: 'BERT Language Understanding', abstract: '...' },
166
+ * { title: 'Object Detection with YOLO', abstract: '...' }
167
+ * ]
168
+ *
169
+ * const clusters = await zai.group(papers, {
170
+ * instructions: 'Group by research area',
171
+ * chunkLength: 10000 // Allow more tokens for detailed abstracts
172
+ * })
173
+ * // Result: Groups papers by topic (NLP, Computer Vision, etc.)
174
+ * ```
175
+ *
176
+ * @example With initial seed groups
177
+ * ```typescript
178
+ * const tasks = [
179
+ * "Fix login bug",
180
+ * "Update documentation",
181
+ * "Add dark mode",
182
+ * "Optimize database queries"
183
+ * ]
184
+ *
185
+ * const grouped = await zai.group(tasks, {
186
+ * instructions: 'Categorize development tasks',
187
+ * initialGroups: [
188
+ * { id: 'bugs', label: 'Bug Fixes', elements: [] },
189
+ * { id: 'features', label: 'New Features', elements: [] },
190
+ * { id: 'docs', label: 'Documentation', elements: [] },
191
+ * { id: 'performance', label: 'Performance', elements: [] }
192
+ * ]
193
+ * })
194
+ * ```
195
+ */
46
196
  group<T>(input: Array<T>, options?: Options): Response<Array<Group<T>>, Record<string, T[]>>
47
197
  }
48
198
  }
@@ -82,7 +82,125 @@ const _Labels = z.record(z.string().min(1).max(250), z.string()).superRefine((la
82
82
 
83
83
  declare module '@botpress/zai' {
84
84
  interface Zai {
85
- /** Tags the provided input with a list of predefined labels */
85
+ /**
86
+ * Tags input with multiple labels, each with explanation, value, and confidence level.
87
+ *
88
+ * This operation evaluates input against multiple categories simultaneously, providing
89
+ * nuanced confidence levels (ABSOLUTELY_YES, PROBABLY_YES, AMBIGUOUS, PROBABLY_NOT, ABSOLUTELY_NOT).
90
+ * Perfect for content classification, intent detection, and multi-criteria evaluation.
91
+ *
92
+ * @param input - The data to label (text, object, or any value)
93
+ * @param labels - Object mapping label keys to their descriptions
94
+ * @param options - Configuration for examples, instructions, and chunking
95
+ * @returns Response with detailed results per label (explanation, value, confidence), simplified to booleans
96
+ *
97
+ * @example Content moderation
98
+ * ```typescript
99
+ * const comment = "This is a great article! Click here for cheap products!"
100
+ *
101
+ * const result = await zai.label(comment, {
102
+ * spam: 'Is this spam or promotional content?',
103
+ * helpful: 'Is this comment helpful and constructive?',
104
+ * profanity: 'Does this contain profanity or offensive language?'
105
+ * }).result()
106
+ *
107
+ * // result.output:
108
+ * // {
109
+ * // spam: { value: true, confidence: 0.5, explanation: 'Contains promotional link...' },
110
+ * // helpful: { value: true, confidence: 1, explanation: 'Positive feedback...' },
111
+ * // profanity: { value: false, confidence: 1, explanation: 'No offensive language' }
112
+ * // }
113
+ *
114
+ * // Simplified (when awaited directly):
115
+ * const simple = await zai.label(comment, { spam: 'Is this spam?' })
116
+ * // simple: { spam: true }
117
+ * ```
118
+ *
119
+ * @example Intent classification
120
+ * ```typescript
121
+ * const message = "I can't log in to my account"
122
+ *
123
+ * const intents = await zai.label(message, {
124
+ * technical_issue: 'Is this a technical problem?',
125
+ * urgent: 'Does this require immediate attention?',
126
+ * needs_human: 'Should this be escalated to a human agent?',
127
+ * billing_related: 'Is this about billing or payments?'
128
+ * })
129
+ * // Returns boolean for each intent
130
+ * ```
131
+ *
132
+ * @example Sentiment analysis with nuance
133
+ * ```typescript
134
+ * const review = "The product is okay, but shipping was slow"
135
+ *
136
+ * const { output } = await zai.label(review, {
137
+ * positive: 'Is the overall sentiment positive?',
138
+ * negative: 'Is the overall sentiment negative?',
139
+ * mixed: 'Does this express mixed feelings?'
140
+ * }).result()
141
+ *
142
+ * // Check confidence levels
143
+ * if (output.mixed.confidence > 0.5) {
144
+ * console.log('Mixed sentiment detected:', output.mixed.explanation)
145
+ * }
146
+ * ```
147
+ *
148
+ * @example Product categorization
149
+ * ```typescript
150
+ * const product = {
151
+ * name: 'Wireless Headphones',
152
+ * description: 'Noise-canceling Bluetooth headphones for music lovers',
153
+ * price: 199
154
+ * }
155
+ *
156
+ * const categories = await zai.label(product, {
157
+ * electronics: 'Is this an electronic device?',
158
+ * audio: 'Is this audio equipment?',
159
+ * premium: 'Is this a premium/luxury product?',
160
+ * portable: 'Is this portable/mobile?'
161
+ * })
162
+ * // Returns: { electronics: true, audio: true, premium: true, portable: true }
163
+ * ```
164
+ *
165
+ * @example With examples for consistency
166
+ * ```typescript
167
+ * const result = await zai.label(email, {
168
+ * urgent: 'Requires immediate response',
169
+ * complaint: 'Customer is dissatisfied'
170
+ * }, {
171
+ * examples: [
172
+ * {
173
+ * input: 'ASAP! System is down!',
174
+ * labels: {
175
+ * urgent: { label: 'ABSOLUTELY_YES', explanation: 'Critical issue' },
176
+ * complaint: { label: 'PROBABLY_YES', explanation: 'Implicit complaint' }
177
+ * }
178
+ * }
179
+ * ],
180
+ * instructions: 'Consider tone, urgency keywords, and context'
181
+ * })
182
+ * ```
183
+ *
184
+ * @example Understanding confidence levels
185
+ * ```typescript
186
+ * const { output } = await zai.label(text, labels).result()
187
+ *
188
+ * // Confidence values:
189
+ * // ABSOLUTELY_YES: confidence = 1.0, value = true
190
+ * // PROBABLY_YES: confidence = 0.5, value = true
191
+ * // AMBIGUOUS: confidence = 0, value = false
192
+ * // PROBABLY_NOT: confidence = 0.5, value = false
193
+ * // ABSOLUTELY_NOT: confidence = 1.0, value = false
194
+ *
195
+ * Object.entries(output).forEach(([key, result]) => {
196
+ * if (result.value && result.confidence === 1) {
197
+ * console.log(`Definitely ${key}:`, result.explanation)
198
+ * } else if (result.value && result.confidence === 0.5) {
199
+ * console.log(`Probably ${key}:`, result.explanation)
200
+ * }
201
+ * })
202
+ * ```
203
+ */
86
204
  label<T extends string>(
87
205
  input: unknown,
88
206
  labels: Labels<T>,