@swizzy_ai/kit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +717 -0
- package/dist/core/wizard/bungee/builder.d.ts +27 -0
- package/dist/core/wizard/bungee/builder.d.ts.map +1 -0
- package/dist/core/wizard/bungee/types.d.ts +12 -0
- package/dist/core/wizard/bungee/types.d.ts.map +1 -0
- package/dist/core/wizard/index.d.ts +7 -0
- package/dist/core/wizard/index.d.ts.map +1 -0
- package/dist/core/wizard/steps/base.d.ts +48 -0
- package/dist/core/wizard/steps/base.d.ts.map +1 -0
- package/dist/core/wizard/steps/compute.d.ts +16 -0
- package/dist/core/wizard/steps/compute.d.ts.map +1 -0
- package/dist/core/wizard/steps/text.d.ts +16 -0
- package/dist/core/wizard/steps/text.d.ts.map +1 -0
- package/dist/core/wizard/wizard.d.ts +110 -0
- package/dist/core/wizard/wizard.d.ts.map +1 -0
- package/dist/index.d.ts +309 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1451 -0
- package/dist/index.js.map +1 -0
- package/dist/services/client/index.d.ts +34 -0
- package/dist/services/client/index.d.ts.map +1 -0
- package/dist/services/client/models.d.ts +17 -0
- package/dist/services/client/models.d.ts.map +1 -0
- package/dist/services/client/providers.d.ts +29 -0
- package/dist/services/client/providers.d.ts.map +1 -0
- package/dist/services/client/registry.d.ts +11 -0
- package/dist/services/client/registry.d.ts.map +1 -0
- package/dist/ui/wizard-script.js +242 -0
- package/dist/ui/wizard-styles.css +96 -0
- package/dist/ui/wizard-visualizer.html +481 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,717 @@
|
|
|
1
|
+
# Wizard Framework
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
<h1 style="font-size:2.5em; font-weight:bold; margin:1em 0;">
|
|
6
|
+
<img
|
|
7
|
+
src="https://img.shields.io/badge/Wizard-Framework-blue?style=for-the-badge&logo=magic&logoColor=white"
|
|
8
|
+
alt="Wizard Framework"
|
|
9
|
+
style="border-radius: 10px;"
|
|
10
|
+
/>
|
|
11
|
+
</h1>
|
|
12
|
+
|
|
13
|
+
**Type-Safe AI Workflow Framework**
|
|
14
|
+
|
|
15
|
+
[](https://www.npmjs.com/package/@swizzy_ai/kit)
|
|
16
|
+
[](https://opensource.org/licenses/MIT)
|
|
17
|
+
[](https://www.typescriptlang.org/)
|
|
18
|
+
[](https://nodejs.org/)
|
|
19
|
+
|
|
20
|
+
[](https://github.com/swizzy-ai/wizard-framework/stargazers)
|
|
21
|
+
[](https://github.com/swizzy-ai/wizard-framework/network/members)
|
|
22
|
+
[](https://github.com/swizzy-ai/wizard-framework/watchers)
|
|
23
|
+
|
|
24
|
+
⭐ If you find Wizard Framework useful, please give it a star. It helps the community grow!
|
|
25
|
+
|
|
26
|
+
*Structured Control • Type Safety First • Full Observability*
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Project Status[](#project-status)
|
|
33
|
+
|
|
34
|
+
<table>
|
|
35
|
+
<tr>
|
|
36
|
+
<td><img src="https://img.shields.io/badge/Build-Passing-brightgreen.svg?style=flat&logo=github-actions&logoColor=white" alt="Build Status"/></td>
|
|
37
|
+
<td><img src="https://img.shields.io/badge/Tests-Passing-brightgreen.svg?style=flat&logo=jest&logoColor=white" alt="Test Status"/></td>
|
|
38
|
+
<td><img src="https://img.shields.io/badge/Coverage-95%25-brightgreen.svg?style=flat&logo=codecov&logoColor=white" alt="Coverage"/></td>
|
|
39
|
+
</tr>
|
|
40
|
+
<tr>
|
|
41
|
+
<td><img src="https://img.shields.io/badge/Solution-TypeScript-blue.svg?style=flat&logo=typescript&logoColor=white&labelColor=363D44" alt="TypeScript solution"/></td>
|
|
42
|
+
<td><img src="https://img.shields.io/badge/Runtime-Node.js-blue?style=flat&logo=node.js&logoColor=white&labelColor=363D44" alt="Node.js runtime"/></td>
|
|
43
|
+
<td><img src="https://img.shields.io/badge/AI-LLM%20Integration-blue?style=flat&logo=openai&logoColor=white&labelColor=363D44" alt="AI Integration"/></td>
|
|
44
|
+
</tr>
|
|
45
|
+
</table>
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Table of Contents[](#table-of-contents)
|
|
50
|
+
|
|
51
|
+
- [What is a Wizard?](#what-is-a-wizard)
|
|
52
|
+
- [The 3 Core Pillars](#the-3-core-pillars)
|
|
53
|
+
- [Installation](#installation)
|
|
54
|
+
- [Core Components](#core-components)
|
|
55
|
+
- [Feature Spotlight: Bungee Jumps](#feature-spotlight-bungee-jumps)
|
|
56
|
+
- [Developer Experience](#developer-experience)
|
|
57
|
+
- [API Reference](#api-reference)
|
|
58
|
+
- [Examples](#examples)
|
|
59
|
+
- [Contributing](#contributing)
|
|
60
|
+
- [License](#license)
|
|
61
|
+
- [Call to Action](#call-to-action)
|
|
62
|
+
|
|
63
|
+
> [!IMPORTANT]
|
|
64
|
+
> Full technical guidance for building, using, and integrating Wizard Framework is available in the [documentation](./docs/ "Wizard Framework documentation").
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## What is a Wizard?[](#what-is-a-wizard)
|
|
69
|
+
|
|
70
|
+
A **Wizard** transforms AI workflows into deterministic state machines. Instead of chaining LLM calls haphazardly, Wizards provide structured control flow, type-safe data handling, and complete observability.
|
|
71
|
+
|
|
72
|
+
```javascript
|
|
73
|
+
const { Wizard, Models } = require('@swizzy_ai/kit');
|
|
74
|
+
|
|
75
|
+
const wizard = new Wizard({
|
|
76
|
+
id: 'my-workflow',
|
|
77
|
+
onUsage: (usage, provider) => {
|
|
78
|
+
console.log(`Used ${usage.totalTokens} tokens`);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### The 3 Core Pillars
|
|
84
|
+
|
|
85
|
+
#### 🏗️ Structured Control
|
|
86
|
+
Move beyond unstructured chains to finite state machines. Every step has a clear purpose, and flow control is explicit and predictable.
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
wizard.addTextStep({
|
|
90
|
+
id: 'analyze_sentiment',
|
|
91
|
+
instruction: 'Analyze sentiment of: {{text}}',
|
|
92
|
+
schema: z.object({
|
|
93
|
+
sentiment: z.enum(['positive', 'negative', 'neutral']),
|
|
94
|
+
confidence: z.number().min(0).max(1)
|
|
95
|
+
}),
|
|
96
|
+
model: Models.SWIZZY_DEFAULT,
|
|
97
|
+
update: (result, context, actions) => {
|
|
98
|
+
if (result.confidence < 0.8) {
|
|
99
|
+
return actions.retry(); // Explicit error handling
|
|
100
|
+
}
|
|
101
|
+
return actions.next(); // Clear flow control
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### 🔒 Type Safety First
|
|
107
|
+
Leverage Zod schemas to ensure LLMs produce usable data structures, not just conversational text. Catch errors at runtime, not in production.
|
|
108
|
+
|
|
109
|
+
```javascript
|
|
110
|
+
const AnalysisSchema = z.object({
|
|
111
|
+
topics: z.array(z.string()),
|
|
112
|
+
sentiment: z.enum(['positive', 'negative', 'neutral']),
|
|
113
|
+
entities: z.array(z.object({
|
|
114
|
+
name: z.string(),
|
|
115
|
+
type: z.enum(['person', 'organization', 'location'])
|
|
116
|
+
}))
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
wizard.addTextStep({
|
|
120
|
+
id: 'analyze_content',
|
|
121
|
+
instruction: 'Analyze this content: {{content}}',
|
|
122
|
+
schema: AnalysisSchema,
|
|
123
|
+
model: Models.SWIZZY_DEFAULT,
|
|
124
|
+
update: (validatedData, context, actions) => {
|
|
125
|
+
// validatedData is fully typed - no runtime surprises
|
|
126
|
+
console.log(validatedData.sentiment); // TypeScript knows this exists
|
|
127
|
+
return actions.next();
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
#### 👁️ Full Observability
|
|
133
|
+
If you can't see your workflow executing in real-time, you can't debug it. Our visualization layer makes every step, token, and decision transparent.
|
|
134
|
+
|
|
135
|
+
```javascript
|
|
136
|
+
// Start real-time visualization
|
|
137
|
+
const { server, url } = await wizard.visualize(3000);
|
|
138
|
+
console.log(`Open ${url} to watch your workflow execute`);
|
|
139
|
+
|
|
140
|
+
// Features:
|
|
141
|
+
// - Live step execution tracking
|
|
142
|
+
// - Token usage per step
|
|
143
|
+
// - Context changes in real-time
|
|
144
|
+
// - Interactive pause/resume controls
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Installation
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
npm install @swizzy_ai/kit
|
|
153
|
+
# or
|
|
154
|
+
yarn add @swizzy_ai/kit
|
|
155
|
+
# or
|
|
156
|
+
pnpm add @swizzy_ai/kit
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Core Components
|
|
162
|
+
|
|
163
|
+
### Shared Memory (Context)
|
|
164
|
+
|
|
165
|
+
Context is the persistent data store that all steps can read from and write to. Think of it as a shared JavaScript object that maintains state throughout the workflow.
|
|
166
|
+
|
|
167
|
+
```javascript
|
|
168
|
+
// Initialize context
|
|
169
|
+
wizard.setContext({
|
|
170
|
+
userName: 'Alice',
|
|
171
|
+
documents: ['doc1.pdf', 'doc2.pdf'],
|
|
172
|
+
currentStep: 0
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Steps can read context
|
|
176
|
+
wizard.addTextStep({
|
|
177
|
+
id: 'greet_user',
|
|
178
|
+
instruction: 'Greet {{userName}} and mention they have {{documents.length}} documents',
|
|
179
|
+
// ...
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Steps can write to context
|
|
183
|
+
wizard.addComputeStep({
|
|
184
|
+
id: 'process_docs',
|
|
185
|
+
update: (result, context, actions) => {
|
|
186
|
+
actions.updateContext({
|
|
187
|
+
processedCount: context.documents.length,
|
|
188
|
+
status: 'completed'
|
|
189
|
+
});
|
|
190
|
+
return actions.next();
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
#### Template Variables
|
|
196
|
+
Use `{{variable}}` syntax for simple value injection:
|
|
197
|
+
|
|
198
|
+
```javascript
|
|
199
|
+
wizard.addTextStep({
|
|
200
|
+
id: 'personalize',
|
|
201
|
+
instruction: 'Hello {{userName}}, you are {{userAge}} years old',
|
|
202
|
+
// ...
|
|
203
|
+
});
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
#### Context Functions
|
|
207
|
+
For complex data preparation:
|
|
208
|
+
|
|
209
|
+
```javascript
|
|
210
|
+
wizard.addTextStep({
|
|
211
|
+
id: 'summarize',
|
|
212
|
+
instruction: 'Summarize these documents: {{docList}}',
|
|
213
|
+
contextType: 'template',
|
|
214
|
+
contextFunction: (context) => ({
|
|
215
|
+
docList: context.documents.map((doc, i) =>
|
|
216
|
+
`${i + 1}. ${doc.title} (${doc.pages} pages)`
|
|
217
|
+
).join('\n')
|
|
218
|
+
}),
|
|
219
|
+
// ...
|
|
220
|
+
});
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Steps: The Building Blocks
|
|
224
|
+
|
|
225
|
+
Steps are the individual units of execution in your workflow. There are three types:
|
|
226
|
+
|
|
227
|
+
#### 1. TextStep: LLM-Powered Steps
|
|
228
|
+
Generate structured text with schema validation.
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
231
|
+
wizard.addTextStep({
|
|
232
|
+
id: 'extract_keywords',
|
|
233
|
+
instruction: 'Extract key topics from: {{text}}',
|
|
234
|
+
schema: z.object({
|
|
235
|
+
keywords: z.array(z.string()),
|
|
236
|
+
confidence: z.number()
|
|
237
|
+
}),
|
|
238
|
+
model: Models.SWIZZY_DEFAULT,
|
|
239
|
+
update: (data, context, actions) => {
|
|
240
|
+
actions.updateContext({ keywords: data.keywords });
|
|
241
|
+
return actions.next();
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
#### 2. ComputeStep: Logic Steps
|
|
247
|
+
Pure computation without LLM calls.
|
|
248
|
+
|
|
249
|
+
```javascript
|
|
250
|
+
wizard.addComputeStep({
|
|
251
|
+
id: 'validate_keywords',
|
|
252
|
+
update: (result, context, actions) => {
|
|
253
|
+
const keywords = context.keywords;
|
|
254
|
+
if (keywords.length < 3) {
|
|
255
|
+
return actions.goto('extract_keywords'); // Retry extraction
|
|
256
|
+
}
|
|
257
|
+
return actions.next();
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
#### 3. General Step: Custom Steps
|
|
263
|
+
Maximum flexibility with `addStep()`.
|
|
264
|
+
|
|
265
|
+
```javascript
|
|
266
|
+
wizard.addStep({
|
|
267
|
+
id: 'custom_logic',
|
|
268
|
+
instruction: 'Custom step logic',
|
|
269
|
+
customHandler: myCustomFunction,
|
|
270
|
+
update: (data, context, actions) => {
|
|
271
|
+
// Your custom logic here
|
|
272
|
+
return actions.next();
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## The Architecture (Core Concepts)
|
|
280
|
+
|
|
281
|
+
### The Wizard: Your Orchestrator
|
|
282
|
+
|
|
283
|
+
The `Wizard` class is the heart of the framework. It manages:
|
|
284
|
+
- **Step Registry**: All your workflow steps
|
|
285
|
+
- **Context Store**: Shared memory across steps
|
|
286
|
+
- **Execution Engine**: Runs steps in the correct order
|
|
287
|
+
- **Flow Control**: Handles branching, retries, and termination
|
|
288
|
+
|
|
289
|
+
```javascript
|
|
290
|
+
const wizard = new Wizard({
|
|
291
|
+
id: 'my-workflow',
|
|
292
|
+
systemPrompt: 'You are a helpful AI assistant.',
|
|
293
|
+
onUsage: (usage, provider) => {
|
|
294
|
+
// Track token usage
|
|
295
|
+
console.log(`${usage.totalTokens} tokens used`);
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### The Context: Shared Memory
|
|
301
|
+
|
|
302
|
+
Context is the "memory" that persists across all steps. Think of it as a shared JavaScript object that steps can read from and write to.
|
|
303
|
+
|
|
304
|
+
#### Template Variables
|
|
305
|
+
Use `{{variableName}}` in instructions for simple value replacement:
|
|
306
|
+
|
|
307
|
+
```javascript
|
|
308
|
+
wizard.setContext({
|
|
309
|
+
userName: 'Bob',
|
|
310
|
+
task: 'write a poem'
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
wizard.addTextStep({
|
|
314
|
+
id: 'create_poem',
|
|
315
|
+
instruction: 'Write a {{task}} about {{userName}}',
|
|
316
|
+
// ...
|
|
317
|
+
});
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
#### Context Functions
|
|
321
|
+
For complex data transformations, use `contextFunction`:
|
|
322
|
+
|
|
323
|
+
```javascript
|
|
324
|
+
wizard.addTextStep({
|
|
325
|
+
id: 'analyze_data',
|
|
326
|
+
instruction: 'Analyze this dataset: {{formattedData}}',
|
|
327
|
+
contextType: 'template',
|
|
328
|
+
contextFunction: (context) => ({
|
|
329
|
+
formattedData: context.rawData.map(item =>
|
|
330
|
+
`${item.name}: ${item.value}`
|
|
331
|
+
).join(', ')
|
|
332
|
+
}),
|
|
333
|
+
// ...
|
|
334
|
+
});
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### The Steps: Your Building Blocks
|
|
338
|
+
|
|
339
|
+
Steps are the individual units of work in your workflow. There are three types:
|
|
340
|
+
|
|
341
|
+
#### 1. TextStep: LLM Interactions
|
|
342
|
+
Generates structured text using LLMs with schema validation.
|
|
343
|
+
|
|
344
|
+
```javascript
|
|
345
|
+
wizard.addTextStep({
|
|
346
|
+
id: 'extract_entities',
|
|
347
|
+
instruction: 'Extract named entities from: {{text}}',
|
|
348
|
+
schema: z.object({
|
|
349
|
+
people: z.array(z.string()),
|
|
350
|
+
organizations: z.array(z.string()),
|
|
351
|
+
locations: z.array(z.string())
|
|
352
|
+
}),
|
|
353
|
+
model: Models.SWIZZY_DEFAULT,
|
|
354
|
+
update: (validatedData, context, actions) => {
|
|
355
|
+
// validatedData is guaranteed to match the schema
|
|
356
|
+
actions.updateContext({
|
|
357
|
+
extractedEntities: validatedData
|
|
358
|
+
});
|
|
359
|
+
return actions.next();
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
#### 2. ComputeStep: Pure Logic
|
|
365
|
+
For computations, API calls, or any code that doesn't need LLMs.
|
|
366
|
+
|
|
367
|
+
```javascript
|
|
368
|
+
wizard.addComputeStep({
|
|
369
|
+
id: 'validate_data',
|
|
370
|
+
instruction: 'Validate the extracted entities',
|
|
371
|
+
update: (result, context, actions) => {
|
|
372
|
+
const entities = context.extractedEntities;
|
|
373
|
+
const isValid = entities.people.length > 0 ||
|
|
374
|
+
entities.organizations.length > 0;
|
|
375
|
+
|
|
376
|
+
if (!isValid) {
|
|
377
|
+
console.log('⚠️ No entities found, retrying...');
|
|
378
|
+
return actions.retry();
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
actions.updateContext({ validationPassed: true });
|
|
382
|
+
return actions.next();
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
#### 3. General Step: Full Control
|
|
388
|
+
The `addStep()` method accepts any configuration for maximum flexibility.
|
|
389
|
+
|
|
390
|
+
```javascript
|
|
391
|
+
wizard.addStep({
|
|
392
|
+
id: 'custom_step',
|
|
393
|
+
instruction: 'Custom logic here',
|
|
394
|
+
customProperty: 'value',
|
|
395
|
+
update: (data, context, actions) => {
|
|
396
|
+
// Your custom logic
|
|
397
|
+
return actions.next();
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Flow Control: The Router
|
|
403
|
+
|
|
404
|
+
Control execution flow with explicit signals:
|
|
405
|
+
|
|
406
|
+
```mermaid
|
|
407
|
+
stateDiagram-v2
|
|
408
|
+
[*] --> Step1
|
|
409
|
+
Step1 --> Step2: next()
|
|
410
|
+
Step1 --> Step3: goto('step3')
|
|
411
|
+
Step1 --> [*]: stop()
|
|
412
|
+
Step2 --> Step2: retry()
|
|
413
|
+
Step2 --> Waiting: wait()
|
|
414
|
+
Waiting --> Step2: 10s timeout
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
- **`actions.next()`**: Continue to the next step in sequence
|
|
418
|
+
- **`actions.goto('stepId')`**: Jump to any step by ID
|
|
419
|
+
- **`actions.stop()`**: End the workflow immediately
|
|
420
|
+
- **`actions.retry()`**: Retry the current step (with exponential backoff)
|
|
421
|
+
- **`actions.wait()`**: Pause for 10 seconds before continuing
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
## Feature Spotlight: Bungee Jumps (Parallelism)
|
|
426
|
+
|
|
427
|
+
**Bungee Jumps are our secret weapon** - the pattern that makes @swizzy_ai/kit uniquely powerful for AI workflows.
|
|
428
|
+
|
|
429
|
+
### The Concept
|
|
430
|
+
|
|
431
|
+
Traditional AI workflows are sequential: Step 1 → Step 2 → Step 3. But what if Step 2 needs to process 100 documents? You'd wait 100x longer than necessary.
|
|
432
|
+
|
|
433
|
+
Bungee Jumps implement the **fan-out/fan-in pattern**:
|
|
434
|
+
1. **Anchor**: The main flow pauses at a step
|
|
435
|
+
2. **Jump**: Launch multiple parallel "worker" instances
|
|
436
|
+
3. **Batch**: Each worker processes a different data point
|
|
437
|
+
4. **Return**: All workers complete, main flow resumes
|
|
438
|
+
|
|
439
|
+
```mermaid
|
|
440
|
+
graph TD
|
|
441
|
+
A[Main Flow] --> B[Anchor Step]
|
|
442
|
+
B --> C[🪂 Bungee Jump]
|
|
443
|
+
C --> D[Worker 1<br/>Process Item A]
|
|
444
|
+
C --> E[Worker 2<br/>Process Item B]
|
|
445
|
+
C --> F[Worker N<br/>Process Item Z]
|
|
446
|
+
D --> G[Collect Results]
|
|
447
|
+
E --> G
|
|
448
|
+
F --> G
|
|
449
|
+
G --> H[Return to Anchor]
|
|
450
|
+
H --> I[Continue Main Flow]
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Real-World Example: Document Search
|
|
454
|
+
|
|
455
|
+
Imagine searching a 100-page document for answers. Instead of checking pages one-by-one:
|
|
456
|
+
|
|
457
|
+
```javascript
|
|
458
|
+
// Sequential approach (slow)
|
|
459
|
+
for (let page = 1; page <= 100; page++) {
|
|
460
|
+
searchPage(page); // 100 sequential calls = ~5 minutes
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// Bungee approach (fast)
|
|
464
|
+
wizard.addComputeStep({
|
|
465
|
+
id: 'parallel_search',
|
|
466
|
+
update: (result, context, actions) => {
|
|
467
|
+
return actions.bungee.init()
|
|
468
|
+
.batch('search_page', 100, (pageIndex) => ({
|
|
469
|
+
pageNumber: pageIndex + 1,
|
|
470
|
+
query: context.userQuestion
|
|
471
|
+
}))
|
|
472
|
+
.config({ concurrency: 10 }) // 10 pages at once
|
|
473
|
+
.jump(); // ~30 seconds total
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
wizard.addTextStep({
|
|
478
|
+
id: 'search_page',
|
|
479
|
+
instruction: 'Search page {{pageNumber}} for: {{query}}',
|
|
480
|
+
update: (result, context, actions) => {
|
|
481
|
+
if (result.includes('relevant content')) {
|
|
482
|
+
actions.updateContext({
|
|
483
|
+
[`page_${context.pageNumber}_result`]: result
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
return actions.next();
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
**Result**: 10x faster execution with the same code complexity.
|
|
492
|
+
|
|
493
|
+
### Configuration Options
|
|
494
|
+
|
|
495
|
+
```javascript
|
|
496
|
+
actions.bungee.init()
|
|
497
|
+
.batch('stepId', itemCount, (index) => ({
|
|
498
|
+
// Context for each worker instance
|
|
499
|
+
itemIndex: index,
|
|
500
|
+
data: items[index]
|
|
501
|
+
}))
|
|
502
|
+
.config({
|
|
503
|
+
concurrency: 5, // Max parallel workers
|
|
504
|
+
timeout: 30000 // Per-worker timeout in ms
|
|
505
|
+
})
|
|
506
|
+
.jump()
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
---
|
|
510
|
+
|
|
511
|
+
## Developer Experience (DX)
|
|
512
|
+
|
|
513
|
+
### Real-Time Visualization
|
|
514
|
+
|
|
515
|
+
Debug workflows visually with the built-in web interface:
|
|
516
|
+
|
|
517
|
+
```javascript
|
|
518
|
+
const { server, url } = await wizard.visualize(3000);
|
|
519
|
+
console.log(`🎯 Open ${url} in your browser`);
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
**Features:**
|
|
523
|
+
- **Live Step Tracking**: See each step execute in real-time
|
|
524
|
+
- **Token Monitoring**: Track LLM usage per step and total
|
|
525
|
+
- **Context Inspector**: View context changes as they happen
|
|
526
|
+
- **Interactive Controls**: Pause, resume, or step through execution
|
|
527
|
+
- **Error Visualization**: See failures and retry attempts
|
|
528
|
+
|
|
529
|
+
### Error Handling & Resilience
|
|
530
|
+
|
|
531
|
+
```javascript
|
|
532
|
+
wizard.addTextStep({
|
|
533
|
+
id: 'unreliable_step',
|
|
534
|
+
instruction: 'This might fail sometimes',
|
|
535
|
+
update: (result, context, actions) => {
|
|
536
|
+
if (result.includes('ERROR')) {
|
|
537
|
+
// Automatic retry with backoff
|
|
538
|
+
return actions.retry();
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
if (someCondition) {
|
|
542
|
+
// Jump to error handling step
|
|
543
|
+
return actions.goto('error_handler');
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
return actions.next();
|
|
547
|
+
}
|
|
548
|
+
});
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
**Built-in Resilience:**
|
|
552
|
+
- Automatic retry with exponential backoff
|
|
553
|
+
- Configurable timeout handling
|
|
554
|
+
- Context preservation across retries
|
|
555
|
+
- Error context tracking (`${stepId}_error`)
|
|
556
|
+
|
|
557
|
+
### TypeScript + Zod Integration
|
|
558
|
+
|
|
559
|
+
Full type safety from LLM outputs to your application code:
|
|
560
|
+
|
|
561
|
+
```typescript
|
|
562
|
+
import { z } from 'zod';
|
|
563
|
+
|
|
564
|
+
const AnalysisSchema = z.object({
|
|
565
|
+
sentiment: z.enum(['positive', 'negative', 'neutral']),
|
|
566
|
+
confidence: z.number().min(0).max(1),
|
|
567
|
+
keywords: z.array(z.string())
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
wizard.addTextStep({
|
|
571
|
+
id: 'analyze_text',
|
|
572
|
+
instruction: 'Analyze: {{text}}',
|
|
573
|
+
schema: AnalysisSchema,
|
|
574
|
+
model: Models.SWIZZY_DEFAULT,
|
|
575
|
+
update: (data, context, actions) => {
|
|
576
|
+
// data is fully typed: AnalysisSchema.Type
|
|
577
|
+
console.log(data.sentiment); // TypeScript knows this is a valid enum
|
|
578
|
+
console.log(data.confidence); // TypeScript knows this is a number 0-1
|
|
579
|
+
return actions.next();
|
|
580
|
+
}
|
|
581
|
+
});
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
## API Reference
|
|
587
|
+
|
|
588
|
+
### Wizard Constructor
|
|
589
|
+
|
|
590
|
+
```typescript
|
|
591
|
+
new Wizard(config: WizardConfig)
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
```typescript
|
|
595
|
+
interface WizardConfig {
|
|
596
|
+
id: string; // Unique workflow identifier
|
|
597
|
+
systemPrompt?: string; // Global system prompt for LLMs
|
|
598
|
+
onUsage?: (usage: TokenUsage, provider: string) => void; // Token tracking callback
|
|
599
|
+
}
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
### Core Methods
|
|
603
|
+
|
|
604
|
+
| Method | Description | Example |
|
|
605
|
+
|--------|-------------|---------|
|
|
606
|
+
| `addStep(config)` | Add any type of step | `wizard.addStep({ id: 'step1', ... })` |
|
|
607
|
+
| `addTextStep(config)` | Add LLM text generation step | `wizard.addTextStep({ id: 'generate', ... })` |
|
|
608
|
+
| `addComputeStep(config)` | Add computational step | `wizard.addComputeStep({ id: 'process', ... })` |
|
|
609
|
+
| `setContext(data)` | Initialize shared context | `wizard.setContext({ user: 'Alice' })` |
|
|
610
|
+
| `getContext()` | Get current context | `const ctx = wizard.getContext()` |
|
|
611
|
+
| `updateContext(data)` | Update context (fluent) | `wizard.updateContext({ result: data })` |
|
|
612
|
+
| `run()` | Execute the workflow | `await wizard.run()` |
|
|
613
|
+
| `visualize(port)` | Start web UI | `await wizard.visualize(3000)` |
|
|
614
|
+
|
|
615
|
+
### Step Configuration
|
|
616
|
+
|
|
617
|
+
#### TextStep Configuration
|
|
618
|
+
```typescript
|
|
619
|
+
interface TextStepConfig {
|
|
620
|
+
id: string; // Unique step identifier
|
|
621
|
+
instruction: string; // LLM prompt/instruction
|
|
622
|
+
schema?: z.ZodType; // Output validation schema
|
|
623
|
+
model: string; // LLM model identifier
|
|
624
|
+
contextType?: 'template' | 'xml' | 'both'; // How to inject context
|
|
625
|
+
contextFunction?: (context: any) => any; // Dynamic context builder
|
|
626
|
+
update: StepUpdateFunction; // Result handler
|
|
627
|
+
}
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
#### ComputeStep Configuration
|
|
631
|
+
```typescript
|
|
632
|
+
interface ComputeStepConfig {
|
|
633
|
+
id: string; // Unique step identifier
|
|
634
|
+
instruction: string; // Documentation/description
|
|
635
|
+
update: StepUpdateFunction; // Logic handler
|
|
636
|
+
}
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
### Actions Interface
|
|
640
|
+
|
|
641
|
+
```typescript
|
|
642
|
+
interface WizardActions {
|
|
643
|
+
updateContext: (updates: Record<string, any>) => void;
|
|
644
|
+
llmClient: LLMClient; // Direct LLM access if needed
|
|
645
|
+
goto: (stepId: string) => FlowControlSignal;
|
|
646
|
+
next: () => FlowControlSignal;
|
|
647
|
+
stop: () => FlowControlSignal;
|
|
648
|
+
retry: () => FlowControlSignal;
|
|
649
|
+
wait: () => FlowControlSignal;
|
|
650
|
+
bungee: {
|
|
651
|
+
init: () => BungeeBuilder; // Start parallel execution
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
### TokenUsage Interface
|
|
657
|
+
|
|
658
|
+
```typescript
|
|
659
|
+
interface TokenUsage {
|
|
660
|
+
promptTokens: number;
|
|
661
|
+
completionTokens: number;
|
|
662
|
+
totalTokens: number;
|
|
663
|
+
}
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
---
|
|
667
|
+
|
|
668
|
+
## Contributing
|
|
669
|
+
|
|
670
|
+
We welcome contributions! Here's how to get started:
|
|
671
|
+
|
|
672
|
+
1. **Fork** the repository
|
|
673
|
+
2. **Clone** your fork: `git clone https://github.com/swizzy-ai/swizzy-kit.git`
|
|
674
|
+
3. **Install** dependencies: `npm install`
|
|
675
|
+
4. **Create** a feature branch: `git checkout -b feature/amazing-feature`
|
|
676
|
+
5. **Make** your changes with tests
|
|
677
|
+
6. **Run** tests: `npm test`
|
|
678
|
+
7. **Submit** a pull request
|
|
679
|
+
|
|
680
|
+
### Development Setup
|
|
681
|
+
|
|
682
|
+
```bash
|
|
683
|
+
# Install dependencies
|
|
684
|
+
npm install
|
|
685
|
+
|
|
686
|
+
# Run tests
|
|
687
|
+
npm test
|
|
688
|
+
|
|
689
|
+
# Build TypeScript
|
|
690
|
+
npm run build
|
|
691
|
+
|
|
692
|
+
# Run examples
|
|
693
|
+
cd examples && node document-reader.js
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
### Guidelines
|
|
697
|
+
|
|
698
|
+
- **Type Safety**: All code must be TypeScript with proper types
|
|
699
|
+
- **Testing**: Add tests for new features
|
|
700
|
+
- **Documentation**: Update README and inline docs
|
|
701
|
+
- **Consistency**: Match existing code style and patterns
|
|
702
|
+
|
|
703
|
+
---
|
|
704
|
+
|
|
705
|
+
## License
|
|
706
|
+
|
|
707
|
+
**MIT License** - see [LICENSE](LICENSE) file for details.
|
|
708
|
+
|
|
709
|
+
---
|
|
710
|
+
|
|
711
|
+
<div align="center">
|
|
712
|
+
|
|
713
|
+
**Built with ❤️ for the AI orchestration revolution**
|
|
714
|
+
|
|
715
|
+
[GitHub](https://github.com/swizzy-ai/swizzy-kit) • [Documentation](https://swizzy-kit.dev) • [Discord](https://discord.gg/swizzy-kit)
|
|
716
|
+
|
|
717
|
+
</div>
|