@doclo/flows 0.1.8 → 0.1.9
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 +45 -21
- package/dist/index.js +45 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,41 +1,65 @@
|
|
|
1
1
|
# @doclo/flows
|
|
2
2
|
|
|
3
|
-
Flow
|
|
3
|
+
Flow builder and execution engine for document processing pipelines.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install @doclo/flows
|
|
9
|
-
# or
|
|
10
8
|
pnpm add @doclo/flows
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
## Features
|
|
14
|
-
|
|
15
|
-
- **FlowBuilder** - Declarative API for building document processing flows
|
|
16
|
-
- **FlowExecutor** - Execute flows with automatic dependency resolution
|
|
17
|
-
- **Composite Nodes** - Combine multiple nodes (sequence, parallel, forEach, conditional)
|
|
18
|
-
- **Metrics Aggregation** - Automatic cost and token tracking across flow execution
|
|
19
|
-
|
|
20
11
|
## Usage
|
|
21
12
|
|
|
22
13
|
```typescript
|
|
23
|
-
import {
|
|
14
|
+
import { createFlow, parse, extract } from '@doclo/flows';
|
|
15
|
+
import { createVLMProvider } from '@doclo/providers-llm';
|
|
16
|
+
|
|
17
|
+
const provider = createVLMProvider({
|
|
18
|
+
provider: 'google',
|
|
19
|
+
model: 'gemini-2.5-flash',
|
|
20
|
+
apiKey: process.env.GOOGLE_API_KEY!
|
|
21
|
+
});
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
const schema = {
|
|
24
|
+
type: 'object',
|
|
25
|
+
properties: {
|
|
26
|
+
invoiceNumber: { type: 'string' },
|
|
27
|
+
total: { type: 'number' }
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const flow = createFlow()
|
|
32
|
+
.step('parse', parse({ provider }))
|
|
33
|
+
.step('extract', extract({ provider, schema }))
|
|
29
34
|
.build();
|
|
30
35
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const result = await executor.execute({
|
|
34
|
-
text: "Document content...",
|
|
35
|
-
images: [{ base64: "...", mimeType: "image/jpeg" }]
|
|
36
|
-
});
|
|
36
|
+
const result = await flow.run({ base64: documentBase64 });
|
|
37
|
+
console.log(result.output);
|
|
37
38
|
```
|
|
38
39
|
|
|
40
|
+
## Flow Methods
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
createFlow()
|
|
44
|
+
.step(id, node) // Add a sequential step
|
|
45
|
+
.conditional(id, fn) // Add conditional branching
|
|
46
|
+
.forEach(id, childFlowFn) // Process arrays in parallel
|
|
47
|
+
.output({ name, source }) // Mark explicit output
|
|
48
|
+
.build() // Build executable flow
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Available Nodes
|
|
52
|
+
|
|
53
|
+
Re-exported from `@doclo/nodes`:
|
|
54
|
+
|
|
55
|
+
- `parse` - Extract text from documents
|
|
56
|
+
- `split` - Split multi-doc PDFs into segments
|
|
57
|
+
- `categorize` - Classify documents into categories
|
|
58
|
+
- `extract` - Extract structured data using schema
|
|
59
|
+
- `chunk` - Split text into chunks
|
|
60
|
+
- `combine` - Merge results
|
|
61
|
+
- `trigger` - Execute another flow
|
|
62
|
+
|
|
39
63
|
## License
|
|
40
64
|
|
|
41
65
|
MIT
|
package/dist/index.js
CHANGED
|
@@ -666,6 +666,11 @@ var Flow = class {
|
|
|
666
666
|
stepId: step.id
|
|
667
667
|
}, artifacts);
|
|
668
668
|
artifacts[step.id] = result2.output;
|
|
669
|
+
for (const [key, value] of Object.entries(result2.artifacts)) {
|
|
670
|
+
if (!(key in artifacts)) {
|
|
671
|
+
artifacts[key] = value;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
669
674
|
metrics.push(...result2.metrics);
|
|
670
675
|
completedSteps.push(step.id);
|
|
671
676
|
const stepDuration = Date.now() - stepStartTime;
|
|
@@ -1283,6 +1288,14 @@ function flattenMetrics(childMetrics, prefix) {
|
|
|
1283
1288
|
nested: true
|
|
1284
1289
|
}));
|
|
1285
1290
|
}
|
|
1291
|
+
function flattenArtifacts(childArtifacts, prefix) {
|
|
1292
|
+
const flattened = {};
|
|
1293
|
+
for (const [key, value] of Object.entries(childArtifacts)) {
|
|
1294
|
+
if (key.startsWith("__")) continue;
|
|
1295
|
+
flattened[`${prefix}.${key}`] = value;
|
|
1296
|
+
}
|
|
1297
|
+
return flattened;
|
|
1298
|
+
}
|
|
1286
1299
|
function createConditionalCompositeNode(config) {
|
|
1287
1300
|
const { stepId, categorizeConfig, branches, providers, flows } = config;
|
|
1288
1301
|
return {
|
|
@@ -1351,7 +1364,16 @@ function createConditionalCompositeNode(config) {
|
|
|
1351
1364
|
}
|
|
1352
1365
|
if (ctx?.emit) {
|
|
1353
1366
|
ctx.emit(`${stepId}:branchOutput`, branchResult.output);
|
|
1354
|
-
|
|
1367
|
+
if (branchResult.artifacts) {
|
|
1368
|
+
const flattenedArtifacts = flattenArtifacts(
|
|
1369
|
+
branchResult.artifacts,
|
|
1370
|
+
`${stepId}.branch.${selectedCategory}`
|
|
1371
|
+
);
|
|
1372
|
+
for (const [key, value] of Object.entries(flattenedArtifacts)) {
|
|
1373
|
+
ctx.emit(key, value);
|
|
1374
|
+
}
|
|
1375
|
+
ctx.emit(`${stepId}:branchArtifacts`, branchResult.artifacts);
|
|
1376
|
+
}
|
|
1355
1377
|
}
|
|
1356
1378
|
const categorizeCost = categorizeCostTracker.reduce((sum, m) => sum + (m.costUSD ?? 0), 0);
|
|
1357
1379
|
const branchCost = branchResult.metrics ? branchResult.metrics.reduce((sum, m) => sum + (m.costUSD ?? 0), 0) : 0;
|
|
@@ -1536,6 +1558,18 @@ function createForEachCompositeNode(config) {
|
|
|
1536
1558
|
ctx.emit(`${stepId}:results`, results);
|
|
1537
1559
|
ctx.emit(`${stepId}:successCount`, successCount);
|
|
1538
1560
|
ctx.emit(`${stepId}:failureCount`, failureCount);
|
|
1561
|
+
itemFlowResults.forEach((result, index) => {
|
|
1562
|
+
if (result.artifacts) {
|
|
1563
|
+
const flattenedArtifacts = flattenArtifacts(
|
|
1564
|
+
result.artifacts,
|
|
1565
|
+
`${stepId}.item[${index}]`
|
|
1566
|
+
);
|
|
1567
|
+
for (const [key, value] of Object.entries(flattenedArtifacts)) {
|
|
1568
|
+
ctx.emit(key, value);
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
});
|
|
1572
|
+
ctx.emit(`${stepId}:itemArtifacts`, itemFlowResults.map((r) => r.artifacts));
|
|
1539
1573
|
}
|
|
1540
1574
|
if (ctx?.metrics) {
|
|
1541
1575
|
const provider = providers[splitConfig.providerRef];
|
|
@@ -1755,7 +1789,16 @@ function createRouteCompositeNode(config) {
|
|
|
1755
1789
|
}
|
|
1756
1790
|
if (ctx?.emit) {
|
|
1757
1791
|
ctx.emit(`${stepId}:branchOutput`, branchResult.output);
|
|
1758
|
-
|
|
1792
|
+
if (branchResult.artifacts) {
|
|
1793
|
+
const flattenedArtifacts = flattenArtifacts(
|
|
1794
|
+
branchResult.artifacts,
|
|
1795
|
+
`${stepId}.branch.${selectedBranch}`
|
|
1796
|
+
);
|
|
1797
|
+
for (const [key, value] of Object.entries(flattenedArtifacts)) {
|
|
1798
|
+
ctx.emit(key, value);
|
|
1799
|
+
}
|
|
1800
|
+
ctx.emit(`${stepId}:branchArtifacts`, branchResult.artifacts);
|
|
1801
|
+
}
|
|
1759
1802
|
}
|
|
1760
1803
|
const branchCost = branchResult.metrics ? branchResult.metrics.reduce((sum, m) => sum + (m.costUSD ?? 0), 0) : 0;
|
|
1761
1804
|
const totalMs = Date.now() - t0;
|