@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 CHANGED
@@ -1,41 +1,65 @@
1
1
  # @doclo/flows
2
2
 
3
- Flow orchestration and execution engine for document processing pipelines in the Doclo SDK.
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 { FlowBuilder, FlowExecutor } from '@doclo/flows';
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
- // Build a flow
26
- const flow = new FlowBuilder()
27
- .addStep('categorize', categorizeNode)
28
- .addStep('extract', extractNode, { dependsOn: ['categorize'] })
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
- // Execute the flow
32
- const executor = new FlowExecutor(flow);
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
- ctx.emit(`${stepId}:branchArtifacts`, branchResult.artifacts);
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
- ctx.emit(`${stepId}:branchArtifacts`, branchResult.artifacts);
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;