@botpress/zai 2.4.1 → 2.4.2
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/index.d.ts +1534 -22
- package/dist/operations/answer.js +6 -4
- package/dist/response.js +166 -1
- package/dist/zai.js +106 -0
- package/e2e/data/cache.jsonl +2 -0
- package/package.json +1 -1
- package/src/context.ts +32 -0
- package/src/operations/answer.ts +105 -9
- package/src/operations/check.ts +75 -1
- package/src/operations/extract.ts +67 -1
- package/src/operations/filter.ts +86 -1
- package/src/operations/group.ts +150 -0
- package/src/operations/label.ts +119 -1
- package/src/operations/rate.ts +112 -2
- package/src/operations/rewrite.ts +84 -1
- package/src/operations/sort.ts +111 -9
- package/src/operations/summarize.ts +74 -1
- package/src/operations/text.ts +50 -1
- package/src/response.ts +264 -2
- package/src/zai.ts +214 -0
|
@@ -33,7 +33,90 @@ const Options = z.object({
|
|
|
33
33
|
|
|
34
34
|
declare module '@botpress/zai' {
|
|
35
35
|
interface Zai {
|
|
36
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Rewrites text according to specific instructions while preserving the core meaning.
|
|
38
|
+
*
|
|
39
|
+
* This operation transforms text based on natural language instructions. Perfect for
|
|
40
|
+
* tone adjustment, format conversion, translation, simplification, and style changes.
|
|
41
|
+
*
|
|
42
|
+
* @param original - The text to rewrite
|
|
43
|
+
* @param prompt - Instructions describing how to transform the text
|
|
44
|
+
* @param options - Configuration for examples and length constraints
|
|
45
|
+
* @returns Response promise resolving to the rewritten text
|
|
46
|
+
*
|
|
47
|
+
* @example Change tone
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const original = "Your request has been denied due to insufficient funds."
|
|
50
|
+
* const friendly = await zai.rewrite(
|
|
51
|
+
* original,
|
|
52
|
+
* 'Make this sound more friendly and empathetic'
|
|
53
|
+
* )
|
|
54
|
+
* // Result: "We appreciate your interest, but unfortunately we're unable to proceed..."
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @example Simplify technical content
|
|
58
|
+
* ```typescript
|
|
59
|
+
* const technical = "The API implements RESTful architecture with OAuth 2.0 authentication..."
|
|
60
|
+
* const simple = await zai.rewrite(
|
|
61
|
+
* technical,
|
|
62
|
+
* 'Explain this in simple terms for non-technical users'
|
|
63
|
+
* )
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* @example Professional email conversion
|
|
67
|
+
* ```typescript
|
|
68
|
+
* const casual = "Hey, can you send me that report? Thanks!"
|
|
69
|
+
* const professional = await zai.rewrite(
|
|
70
|
+
* casual,
|
|
71
|
+
* 'Rewrite this as a formal business email'
|
|
72
|
+
* )
|
|
73
|
+
* // Result: "Dear colleague, I would appreciate it if you could share the report..."
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* @example Format conversion
|
|
77
|
+
* ```typescript
|
|
78
|
+
* const paragraph = "First do this. Then do that. Finally do this other thing."
|
|
79
|
+
* const bullets = await zai.rewrite(
|
|
80
|
+
* paragraph,
|
|
81
|
+
* 'Convert this to a bulleted list'
|
|
82
|
+
* )
|
|
83
|
+
* // Result:
|
|
84
|
+
* // - First do this
|
|
85
|
+
* // - Then do that
|
|
86
|
+
* // - Finally do this other thing
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* @example With examples for consistent style
|
|
90
|
+
* ```typescript
|
|
91
|
+
* const result = await zai.rewrite(
|
|
92
|
+
* original,
|
|
93
|
+
* 'Rewrite in our brand voice',
|
|
94
|
+
* {
|
|
95
|
+
* examples: [
|
|
96
|
+
* {
|
|
97
|
+
* input: 'We offer many products.',
|
|
98
|
+
* output: 'Discover our curated collection of innovative solutions.'
|
|
99
|
+
* },
|
|
100
|
+
* {
|
|
101
|
+
* input: 'Contact us for help.',
|
|
102
|
+
* output: "We're here to support your success. Let's connect!"
|
|
103
|
+
* }
|
|
104
|
+
* ],
|
|
105
|
+
* length: 200 // Limit output length
|
|
106
|
+
* }
|
|
107
|
+
* )
|
|
108
|
+
* ```
|
|
109
|
+
*
|
|
110
|
+
* @example Translation-like transformation
|
|
111
|
+
* ```typescript
|
|
112
|
+
* const code = "if (user.isActive && user.hasPermission) { allowAccess() }"
|
|
113
|
+
* const pseudocode = await zai.rewrite(
|
|
114
|
+
* code,
|
|
115
|
+
* 'Convert this code to natural language pseudocode'
|
|
116
|
+
* )
|
|
117
|
+
* // Result: "If the user is active AND has permission, then allow access"
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
37
120
|
rewrite(original: string, prompt: string, options?: Options): Response<string>
|
|
38
121
|
}
|
|
39
122
|
}
|
package/src/operations/sort.ts
CHANGED
|
@@ -35,17 +35,119 @@ type SortingCriteria = Record<
|
|
|
35
35
|
declare module '@botpress/zai' {
|
|
36
36
|
interface Zai {
|
|
37
37
|
/**
|
|
38
|
-
* Sorts
|
|
39
|
-
* Returns the sorted array directly when awaited.
|
|
40
|
-
* Use .result() to get detailed scoring information including why each item got its position.
|
|
38
|
+
* Sorts array items based on natural language sorting criteria.
|
|
41
39
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
40
|
+
* This operation intelligently orders items according to your instructions, understanding
|
|
41
|
+
* complex sorting logic like priority, quality, chronology, or any custom criteria.
|
|
42
|
+
* Perfect for ranking, organizing, and prioritizing lists based on subjective or
|
|
43
|
+
* multi-faceted criteria.
|
|
45
44
|
*
|
|
46
|
-
* @
|
|
47
|
-
*
|
|
48
|
-
*
|
|
45
|
+
* @param input - Array of items to sort
|
|
46
|
+
* @param instructions - Natural language description of how to sort (e.g., "by priority", "newest first")
|
|
47
|
+
* @param options - Configuration for tokens per item
|
|
48
|
+
* @returns Response resolving to the sorted array
|
|
49
|
+
*
|
|
50
|
+
* @example Sort by price
|
|
51
|
+
* ```typescript
|
|
52
|
+
* const products = [
|
|
53
|
+
* { name: 'Laptop', price: 999 },
|
|
54
|
+
* { name: 'Mouse', price: 29 },
|
|
55
|
+
* { name: 'Keyboard', price: 79 }
|
|
56
|
+
* ]
|
|
57
|
+
*
|
|
58
|
+
* const sorted = await zai.sort(products, 'from least expensive to most expensive')
|
|
59
|
+
* // Result: [Mouse ($29), Keyboard ($79), Laptop ($999)]
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @example Sort by priority/urgency
|
|
63
|
+
* ```typescript
|
|
64
|
+
* const tasks = [
|
|
65
|
+
* "Update documentation",
|
|
66
|
+
* "Fix critical security bug",
|
|
67
|
+
* "Add new feature",
|
|
68
|
+
* "System is down - all users affected"
|
|
69
|
+
* ]
|
|
70
|
+
*
|
|
71
|
+
* const prioritized = await zai.sort(tasks, 'by urgency and impact, most urgent first')
|
|
72
|
+
* // Result: ["System is down...", "Fix critical security bug", "Add new feature", "Update documentation"]
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* @example Sort by quality/rating
|
|
76
|
+
* ```typescript
|
|
77
|
+
* const reviews = [
|
|
78
|
+
* "Product is okay",
|
|
79
|
+
* "Absolutely amazing! Best purchase ever!",
|
|
80
|
+
* "Terrible, broke immediately",
|
|
81
|
+
* "Good quality for the price"
|
|
82
|
+
* ]
|
|
83
|
+
*
|
|
84
|
+
* const sorted = await zai.sort(reviews, 'by sentiment, most positive first')
|
|
85
|
+
* // Result: [amazing review, good review, okay review, terrible review]
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
* @example Sort by complexity
|
|
89
|
+
* ```typescript
|
|
90
|
+
* const problems = [
|
|
91
|
+
* "Fix typo in README",
|
|
92
|
+
* "Redesign entire authentication system",
|
|
93
|
+
* "Update a dependency version",
|
|
94
|
+
* "Implement new microservice architecture"
|
|
95
|
+
* ]
|
|
96
|
+
*
|
|
97
|
+
* const sorted = await zai.sort(problems, 'by complexity, simplest first')
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* @example Sort by relevance to query
|
|
101
|
+
* ```typescript
|
|
102
|
+
* const documents = [
|
|
103
|
+
* "Article about cats",
|
|
104
|
+
* "Article about dogs and their training",
|
|
105
|
+
* "Article about dog breeds",
|
|
106
|
+
* "Article about fish"
|
|
107
|
+
* ]
|
|
108
|
+
*
|
|
109
|
+
* const sorted = await zai.sort(
|
|
110
|
+
* documents,
|
|
111
|
+
* 'by relevance to "dog training", most relevant first'
|
|
112
|
+
* )
|
|
113
|
+
* // Result: [dogs and training, dog breeds, cats, fish]
|
|
114
|
+
* ```
|
|
115
|
+
*
|
|
116
|
+
* @example Sort candidates by fit
|
|
117
|
+
* ```typescript
|
|
118
|
+
* const candidates = [
|
|
119
|
+
* { name: 'Alice', experience: 5, skills: ['React', 'Node'] },
|
|
120
|
+
* { name: 'Bob', experience: 10, skills: ['Python', 'ML'] },
|
|
121
|
+
* { name: 'Charlie', experience: 3, skills: ['React', 'TypeScript'] }
|
|
122
|
+
* ]
|
|
123
|
+
*
|
|
124
|
+
* const sorted = await zai.sort(
|
|
125
|
+
* candidates,
|
|
126
|
+
* 'by fit for a senior React developer position, best fit first'
|
|
127
|
+
* )
|
|
128
|
+
* ```
|
|
129
|
+
*
|
|
130
|
+
* @example Sort chronologically
|
|
131
|
+
* ```typescript
|
|
132
|
+
* const events = [
|
|
133
|
+
* "Started the project last month",
|
|
134
|
+
* "Will launch next week",
|
|
135
|
+
* "Met with client yesterday",
|
|
136
|
+
* "Planning meeting tomorrow"
|
|
137
|
+
* ]
|
|
138
|
+
*
|
|
139
|
+
* const chronological = await zai.sort(events, 'in chronological order')
|
|
140
|
+
* // Understands relative time expressions
|
|
141
|
+
* ```
|
|
142
|
+
*
|
|
143
|
+
* @example With token limit per item
|
|
144
|
+
* ```typescript
|
|
145
|
+
* const sorted = await zai.sort(
|
|
146
|
+
* longDocuments,
|
|
147
|
+
* 'by relevance to climate change research',
|
|
148
|
+
* { tokensPerItem: 500 } // Allow 500 tokens per document
|
|
149
|
+
* )
|
|
150
|
+
* ```
|
|
49
151
|
*/
|
|
50
152
|
sort<T>(input: Array<T>, instructions: string, options?: Options): Response<Array<T>, Array<T>>
|
|
51
153
|
}
|
|
@@ -58,7 +58,80 @@ const Options = z.object({
|
|
|
58
58
|
|
|
59
59
|
declare module '@botpress/zai' {
|
|
60
60
|
interface Zai {
|
|
61
|
-
/**
|
|
61
|
+
/**
|
|
62
|
+
* Summarizes text of any length to a target length using intelligent chunking strategies.
|
|
63
|
+
*
|
|
64
|
+
* This operation can handle documents from a few paragraphs to entire books. It uses
|
|
65
|
+
* two strategies based on document size:
|
|
66
|
+
* - **Sliding window**: For moderate documents, processes overlapping chunks iteratively
|
|
67
|
+
* - **Merge sort**: For very large documents, recursively summarizes and merges
|
|
68
|
+
*
|
|
69
|
+
* @param original - The text to summarize
|
|
70
|
+
* @param options - Configuration for length, focus, format, and chunking strategy
|
|
71
|
+
* @returns Response promise resolving to the summary text
|
|
72
|
+
*
|
|
73
|
+
* @example Basic summarization
|
|
74
|
+
* ```typescript
|
|
75
|
+
* const article = "Long article text here..."
|
|
76
|
+
* const summary = await zai.summarize(article, {
|
|
77
|
+
* length: 100 // Target 100 tokens (~75 words)
|
|
78
|
+
* })
|
|
79
|
+
* ```
|
|
80
|
+
*
|
|
81
|
+
* @example Custom focus and format
|
|
82
|
+
* ```typescript
|
|
83
|
+
* const meetingNotes = "... detailed meeting transcript ..."
|
|
84
|
+
* const summary = await zai.summarize(meetingNotes, {
|
|
85
|
+
* length: 200,
|
|
86
|
+
* prompt: 'Key decisions, action items, and next steps',
|
|
87
|
+
* format: 'Bullet points with clear sections for Decisions, Actions, and Next Steps'
|
|
88
|
+
* })
|
|
89
|
+
* ```
|
|
90
|
+
*
|
|
91
|
+
* @example Summarizing very large documents
|
|
92
|
+
* ```typescript
|
|
93
|
+
* const book = await readFile('large-book.txt', 'utf-8') // 100k+ tokens
|
|
94
|
+
* const summary = await zai.summarize(book, {
|
|
95
|
+
* length: 500,
|
|
96
|
+
* intermediateFactor: 4, // Intermediate summaries can be 4x target length
|
|
97
|
+
* prompt: 'Main themes, key events, and character development'
|
|
98
|
+
* })
|
|
99
|
+
* // Automatically uses merge-sort strategy for efficiency
|
|
100
|
+
* ```
|
|
101
|
+
*
|
|
102
|
+
* @example Technical documentation summary
|
|
103
|
+
* ```typescript
|
|
104
|
+
* const docs = "... API documentation ..."
|
|
105
|
+
* const summary = await zai.summarize(docs, {
|
|
106
|
+
* length: 300,
|
|
107
|
+
* prompt: 'Core API endpoints, authentication methods, and rate limits',
|
|
108
|
+
* format: 'Structured markdown with code examples where relevant'
|
|
109
|
+
* })
|
|
110
|
+
* ```
|
|
111
|
+
*
|
|
112
|
+
* @example Adjusting chunking strategy
|
|
113
|
+
* ```typescript
|
|
114
|
+
* const summary = await zai.summarize(document, {
|
|
115
|
+
* length: 150,
|
|
116
|
+
* sliding: {
|
|
117
|
+
* window: 30000, // Process 30k tokens at a time
|
|
118
|
+
* overlap: 500 // 500 token overlap between windows
|
|
119
|
+
* }
|
|
120
|
+
* })
|
|
121
|
+
* ```
|
|
122
|
+
*
|
|
123
|
+
* @example Progress tracking for long documents
|
|
124
|
+
* ```typescript
|
|
125
|
+
* const response = zai.summarize(veryLongDocument, { length: 400 })
|
|
126
|
+
*
|
|
127
|
+
* response.on('progress', (usage) => {
|
|
128
|
+
* console.log(`Progress: ${Math.round(usage.requests.percentage * 100)}%`)
|
|
129
|
+
* console.log(`Tokens used: ${usage.tokens.total}`)
|
|
130
|
+
* })
|
|
131
|
+
*
|
|
132
|
+
* const summary = await response
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
62
135
|
summarize(original: string, options?: Options): Response<string>
|
|
63
136
|
}
|
|
64
137
|
}
|
package/src/operations/text.ts
CHANGED
|
@@ -19,7 +19,56 @@ const Options = z.object({
|
|
|
19
19
|
|
|
20
20
|
declare module '@botpress/zai' {
|
|
21
21
|
interface Zai {
|
|
22
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Generates text content based on a natural language prompt.
|
|
24
|
+
*
|
|
25
|
+
* This operation creates original text content using LLMs with optional length constraints.
|
|
26
|
+
* Perfect for generating descriptions, emails, articles, creative content, and more.
|
|
27
|
+
*
|
|
28
|
+
* @param prompt - Natural language description of what text to generate
|
|
29
|
+
* @param options - Optional configuration for text length
|
|
30
|
+
* @returns Response promise resolving to the generated text
|
|
31
|
+
*
|
|
32
|
+
* @example Product description
|
|
33
|
+
* ```typescript
|
|
34
|
+
* const description = await zai.text(
|
|
35
|
+
* 'Write a compelling product description for eco-friendly bamboo toothbrushes'
|
|
36
|
+
* )
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @example With length constraint
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const tagline = await zai.text(
|
|
42
|
+
* 'Create a catchy tagline for a fitness app',
|
|
43
|
+
* { length: 10 } // ~10 tokens (7-8 words)
|
|
44
|
+
* )
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @example Email generation
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const email = await zai.text(`
|
|
50
|
+
* Write a professional email to a customer explaining
|
|
51
|
+
* that their order will be delayed by 2 days due to weather.
|
|
52
|
+
* Apologize and offer a 10% discount on their next purchase.
|
|
53
|
+
* `, { length: 150 })
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @example Blog post
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const blogPost = await zai.text(`
|
|
59
|
+
* Write an informative blog post about the benefits of meditation
|
|
60
|
+
* for software developers. Include practical tips and scientific research.
|
|
61
|
+
* `, { length: 500 })
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @example Social media content
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const tweet = await zai.text(
|
|
67
|
+
* 'Write an engaging tweet announcing our new AI-powered chatbot feature',
|
|
68
|
+
* { length: 30 } // Twitter-friendly length
|
|
69
|
+
* )
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
23
72
|
text(prompt: string, options?: Options): Response<string>
|
|
24
73
|
}
|
|
25
74
|
}
|
package/src/response.ts
CHANGED
|
@@ -1,13 +1,110 @@
|
|
|
1
1
|
import { Usage, ZaiContext } from './context'
|
|
2
2
|
import { EventEmitter } from './emitter'
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Event types emitted during operation execution.
|
|
6
|
+
*
|
|
7
|
+
* @property progress - Emitted periodically with usage statistics (tokens, cost, requests)
|
|
8
|
+
* @property complete - Emitted when operation completes successfully with the result
|
|
9
|
+
* @property error - Emitted when operation fails with the error
|
|
10
|
+
*/
|
|
5
11
|
export type ResponseEvents<TComplete = any> = {
|
|
12
|
+
/** Emitted during execution with updated usage statistics */
|
|
6
13
|
progress: Usage
|
|
14
|
+
/** Emitted when the operation completes with the full result */
|
|
7
15
|
complete: TComplete
|
|
16
|
+
/** Emitted when the operation fails with an error */
|
|
8
17
|
error: unknown
|
|
9
18
|
}
|
|
10
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Promise-like wrapper for Zai operations with observability and control.
|
|
22
|
+
*
|
|
23
|
+
* Response provides a dual-value system:
|
|
24
|
+
* - **Simplified value**: When awaited directly, returns a simplified result (e.g., boolean for `check()`)
|
|
25
|
+
* - **Full result**: Via `.result()` method, returns `{ output, usage, elapsed }`
|
|
26
|
+
*
|
|
27
|
+
* All Zai operations return a Response instance, allowing you to:
|
|
28
|
+
* - Track progress and usage in real-time
|
|
29
|
+
* - Abort operations
|
|
30
|
+
* - Bind to external abort signals
|
|
31
|
+
* - Get detailed cost and performance metrics
|
|
32
|
+
*
|
|
33
|
+
* @template T - The full output type
|
|
34
|
+
* @template S - The simplified output type (defaults to T)
|
|
35
|
+
*
|
|
36
|
+
* @example Basic usage (simplified)
|
|
37
|
+
* ```typescript
|
|
38
|
+
* // Simplified result (boolean)
|
|
39
|
+
* const isPositive = await zai.check(review, 'Is this positive?')
|
|
40
|
+
* console.log(isPositive) // true or false
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @example Full result with usage
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const response = zai.check(review, 'Is this positive?')
|
|
46
|
+
* const { output, usage, elapsed } = await response.result()
|
|
47
|
+
*
|
|
48
|
+
* console.log(output.value) // true/false
|
|
49
|
+
* console.log(output.explanation) // "The review expresses satisfaction..."
|
|
50
|
+
* console.log(usage.tokens.total) // 150
|
|
51
|
+
* console.log(usage.cost.total) // 0.002
|
|
52
|
+
* console.log(elapsed) // 1234 (ms)
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* @example Progress tracking
|
|
56
|
+
* ```typescript
|
|
57
|
+
* const response = zai.summarize(longDocument, { length: 500 })
|
|
58
|
+
*
|
|
59
|
+
* response.on('progress', (usage) => {
|
|
60
|
+
* console.log(`Progress: ${usage.requests.percentage * 100}%`)
|
|
61
|
+
* console.log(`Tokens: ${usage.tokens.total}`)
|
|
62
|
+
* console.log(`Cost: $${usage.cost.total}`)
|
|
63
|
+
* })
|
|
64
|
+
*
|
|
65
|
+
* const summary = await response
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @example Aborting operations
|
|
69
|
+
* ```typescript
|
|
70
|
+
* const response = zai.extract(hugeDocument, schema)
|
|
71
|
+
*
|
|
72
|
+
* // Abort after 5 seconds
|
|
73
|
+
* setTimeout(() => response.abort('Timeout'), 5000)
|
|
74
|
+
*
|
|
75
|
+
* try {
|
|
76
|
+
* const result = await response
|
|
77
|
+
* } catch (error) {
|
|
78
|
+
* console.log('Operation aborted:', error)
|
|
79
|
+
* }
|
|
80
|
+
* ```
|
|
81
|
+
*
|
|
82
|
+
* @example External abort signal
|
|
83
|
+
* ```typescript
|
|
84
|
+
* const controller = new AbortController()
|
|
85
|
+
* const response = zai.answer(documents, question).bindSignal(controller.signal)
|
|
86
|
+
*
|
|
87
|
+
* // User clicks cancel button
|
|
88
|
+
* cancelButton.onclick = () => controller.abort()
|
|
89
|
+
*
|
|
90
|
+
* const answer = await response
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* @example Error handling
|
|
94
|
+
* ```typescript
|
|
95
|
+
* const response = zai.extract(text, schema)
|
|
96
|
+
*
|
|
97
|
+
* response.on('error', (error) => {
|
|
98
|
+
* console.error('Operation failed:', error)
|
|
99
|
+
* })
|
|
100
|
+
*
|
|
101
|
+
* try {
|
|
102
|
+
* const result = await response
|
|
103
|
+
* } catch (error) {
|
|
104
|
+
* // Handle error
|
|
105
|
+
* }
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
11
108
|
export class Response<T = any, S = T> implements PromiseLike<S> {
|
|
12
109
|
private _promise: Promise<T>
|
|
13
110
|
private _eventEmitter: EventEmitter<ResponseEvents<T>>
|
|
@@ -41,22 +138,107 @@ export class Response<T = any, S = T> implements PromiseLike<S> {
|
|
|
41
138
|
})
|
|
42
139
|
}
|
|
43
140
|
|
|
44
|
-
|
|
141
|
+
/**
|
|
142
|
+
* Subscribes to events emitted during operation execution.
|
|
143
|
+
*
|
|
144
|
+
* @param type - Event type: 'progress', 'complete', or 'error'
|
|
145
|
+
* @param listener - Callback function to handle the event
|
|
146
|
+
* @returns This Response instance for chaining
|
|
147
|
+
*
|
|
148
|
+
* @example Track progress
|
|
149
|
+
* ```typescript
|
|
150
|
+
* response.on('progress', (usage) => {
|
|
151
|
+
* console.log(`${usage.requests.percentage * 100}% complete`)
|
|
152
|
+
* console.log(`Cost: $${usage.cost.total}`)
|
|
153
|
+
* })
|
|
154
|
+
* ```
|
|
155
|
+
*
|
|
156
|
+
* @example Handle completion
|
|
157
|
+
* ```typescript
|
|
158
|
+
* response.on('complete', (result) => {
|
|
159
|
+
* console.log('Operation completed:', result)
|
|
160
|
+
* })
|
|
161
|
+
* ```
|
|
162
|
+
*
|
|
163
|
+
* @example Handle errors
|
|
164
|
+
* ```typescript
|
|
165
|
+
* response.on('error', (error) => {
|
|
166
|
+
* console.error('Operation failed:', error)
|
|
167
|
+
* })
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
45
170
|
public on<K extends keyof ResponseEvents<T>>(type: K, listener: (event: ResponseEvents<T>[K]) => void) {
|
|
46
171
|
this._eventEmitter.on(type, listener)
|
|
47
172
|
return this
|
|
48
173
|
}
|
|
49
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Unsubscribes from events.
|
|
177
|
+
*
|
|
178
|
+
* @param type - Event type to unsubscribe from
|
|
179
|
+
* @param listener - The exact listener function to remove
|
|
180
|
+
* @returns This Response instance for chaining
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* const progressHandler = (usage) => console.log(usage.tokens.total)
|
|
185
|
+
* response.on('progress', progressHandler)
|
|
186
|
+
* // Later...
|
|
187
|
+
* response.off('progress', progressHandler)
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
50
190
|
public off<K extends keyof ResponseEvents<T>>(type: K, listener: (event: ResponseEvents<T>[K]) => void) {
|
|
51
191
|
this._eventEmitter.off(type, listener)
|
|
52
192
|
return this
|
|
53
193
|
}
|
|
54
194
|
|
|
195
|
+
/**
|
|
196
|
+
* Subscribes to an event for a single emission.
|
|
197
|
+
*
|
|
198
|
+
* The listener is automatically removed after being called once.
|
|
199
|
+
*
|
|
200
|
+
* @param type - Event type: 'progress', 'complete', or 'error'
|
|
201
|
+
* @param listener - Callback function to handle the event once
|
|
202
|
+
* @returns This Response instance for chaining
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```typescript
|
|
206
|
+
* response.once('complete', (result) => {
|
|
207
|
+
* console.log('Finished:', result)
|
|
208
|
+
* })
|
|
209
|
+
* ```
|
|
210
|
+
*/
|
|
55
211
|
public once<K extends keyof ResponseEvents<T>>(type: K, listener: (event: ResponseEvents<T>[K]) => void) {
|
|
56
212
|
this._eventEmitter.once(type, listener)
|
|
57
213
|
return this
|
|
58
214
|
}
|
|
59
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Binds an external AbortSignal to this operation.
|
|
218
|
+
*
|
|
219
|
+
* When the signal is aborted, the operation will be cancelled automatically.
|
|
220
|
+
* Useful for integrating with UI cancel buttons or request timeouts.
|
|
221
|
+
*
|
|
222
|
+
* @param signal - AbortSignal to bind
|
|
223
|
+
* @returns This Response instance for chaining
|
|
224
|
+
*
|
|
225
|
+
* @example With AbortController
|
|
226
|
+
* ```typescript
|
|
227
|
+
* const controller = new AbortController()
|
|
228
|
+
* const response = zai.extract(data, schema).bindSignal(controller.signal)
|
|
229
|
+
*
|
|
230
|
+
* // Cancel from elsewhere
|
|
231
|
+
* cancelButton.onclick = () => controller.abort()
|
|
232
|
+
* ```
|
|
233
|
+
*
|
|
234
|
+
* @example With timeout
|
|
235
|
+
* ```typescript
|
|
236
|
+
* const controller = new AbortController()
|
|
237
|
+
* setTimeout(() => controller.abort('Timeout'), 10000)
|
|
238
|
+
*
|
|
239
|
+
* const response = zai.answer(docs, question).bindSignal(controller.signal)
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
60
242
|
public bindSignal(signal: AbortSignal): this {
|
|
61
243
|
if (signal.aborted) {
|
|
62
244
|
this.abort(signal.reason)
|
|
@@ -74,10 +256,49 @@ export class Response<T = any, S = T> implements PromiseLike<S> {
|
|
|
74
256
|
return this
|
|
75
257
|
}
|
|
76
258
|
|
|
259
|
+
/**
|
|
260
|
+
* Aborts the operation in progress.
|
|
261
|
+
*
|
|
262
|
+
* The operation will be cancelled and throw an abort error.
|
|
263
|
+
* Any partial results will not be returned.
|
|
264
|
+
*
|
|
265
|
+
* @param reason - Optional reason for aborting (string or Error)
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```typescript
|
|
269
|
+
* const response = zai.extract(largeDocument, schema)
|
|
270
|
+
*
|
|
271
|
+
* // Abort after 5 seconds
|
|
272
|
+
* setTimeout(() => response.abort('Operation timeout'), 5000)
|
|
273
|
+
*
|
|
274
|
+
* try {
|
|
275
|
+
* await response
|
|
276
|
+
* } catch (error) {
|
|
277
|
+
* console.log('Aborted:', error)
|
|
278
|
+
* }
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
77
281
|
public abort(reason?: string | Error) {
|
|
78
282
|
this._context.controller.abort(reason)
|
|
79
283
|
}
|
|
80
284
|
|
|
285
|
+
/**
|
|
286
|
+
* Promise interface - allows awaiting the Response.
|
|
287
|
+
*
|
|
288
|
+
* When awaited, returns the simplified value (S).
|
|
289
|
+
* Use `.result()` for full output with usage statistics.
|
|
290
|
+
*
|
|
291
|
+
* @param onfulfilled - Success handler
|
|
292
|
+
* @param onrejected - Error handler
|
|
293
|
+
* @returns Promise resolving to simplified value
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* ```typescript
|
|
297
|
+
* // Simplified value
|
|
298
|
+
* const isPositive = await zai.check(review, 'Is positive?')
|
|
299
|
+
* console.log(isPositive) // true
|
|
300
|
+
* ```
|
|
301
|
+
*/
|
|
81
302
|
// oxlint-disable-next-line no-thenable
|
|
82
303
|
public then<TResult1 = S, TResult2 = never>(
|
|
83
304
|
onfulfilled?: ((value: S) => TResult1 | PromiseLike<TResult1>) | null,
|
|
@@ -97,12 +318,53 @@ export class Response<T = any, S = T> implements PromiseLike<S> {
|
|
|
97
318
|
) as PromiseLike<TResult1 | TResult2>
|
|
98
319
|
}
|
|
99
320
|
|
|
321
|
+
/**
|
|
322
|
+
* Promise interface - handles errors.
|
|
323
|
+
*
|
|
324
|
+
* @param onrejected - Error handler
|
|
325
|
+
* @returns Promise resolving to simplified value or error result
|
|
326
|
+
*/
|
|
100
327
|
public catch<TResult = never>(
|
|
101
328
|
onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null
|
|
102
329
|
): PromiseLike<S | TResult> {
|
|
103
330
|
return this._promise.catch(onrejected) as PromiseLike<S | TResult>
|
|
104
331
|
}
|
|
105
332
|
|
|
333
|
+
/**
|
|
334
|
+
* Gets the full result with detailed usage statistics and timing.
|
|
335
|
+
*
|
|
336
|
+
* Unlike awaiting the Response directly (which returns simplified value),
|
|
337
|
+
* this method provides:
|
|
338
|
+
* - `output`: Full operation result (not simplified)
|
|
339
|
+
* - `usage`: Detailed token usage, cost, and request statistics
|
|
340
|
+
* - `elapsed`: Operation duration in milliseconds
|
|
341
|
+
*
|
|
342
|
+
* @returns Promise resolving to full result object
|
|
343
|
+
*
|
|
344
|
+
* @example
|
|
345
|
+
* ```typescript
|
|
346
|
+
* const { output, usage, elapsed } = await zai.check(text, condition).result()
|
|
347
|
+
*
|
|
348
|
+
* console.log(output.value) // true/false
|
|
349
|
+
* console.log(output.explanation) // "The text expresses..."
|
|
350
|
+
* console.log(usage.tokens.total) // 245
|
|
351
|
+
* console.log(usage.cost.total) // 0.0012
|
|
352
|
+
* console.log(elapsed) // 1523 (ms)
|
|
353
|
+
* ```
|
|
354
|
+
*
|
|
355
|
+
* @example Usage statistics breakdown
|
|
356
|
+
* ```typescript
|
|
357
|
+
* const { usage } = await response.result()
|
|
358
|
+
*
|
|
359
|
+
* console.log('Requests:', usage.requests.requests)
|
|
360
|
+
* console.log('Cached:', usage.requests.cached)
|
|
361
|
+
* console.log('Input tokens:', usage.tokens.input)
|
|
362
|
+
* console.log('Output tokens:', usage.tokens.output)
|
|
363
|
+
* console.log('Input cost:', usage.cost.input)
|
|
364
|
+
* console.log('Output cost:', usage.cost.output)
|
|
365
|
+
* console.log('Total cost:', usage.cost.total)
|
|
366
|
+
* ```
|
|
367
|
+
*/
|
|
106
368
|
public async result(): Promise<{
|
|
107
369
|
output: T
|
|
108
370
|
usage: Usage
|