footprintjs 0.2.2 → 0.2.3
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 +73 -39
- package/dist/esm/lib/builder/FlowChartBuilder.js +54 -91
- package/dist/esm/lib/builder/types.js +1 -1
- package/dist/esm/lib/engine/graph/StageNode.js +1 -1
- package/dist/esm/lib/engine/handlers/ChildrenExecutor.js +5 -5
- package/dist/esm/lib/engine/handlers/ContinuationResolver.js +6 -6
- package/dist/esm/lib/engine/handlers/DeciderHandler.js +4 -4
- package/dist/esm/lib/engine/handlers/NodeResolver.js +1 -2
- package/dist/esm/lib/engine/handlers/RuntimeStructureManager.js +1 -2
- package/dist/esm/lib/engine/handlers/SelectorHandler.js +6 -6
- package/dist/esm/lib/engine/narrative/ControlFlowNarrativeGenerator.js +13 -18
- package/dist/esm/lib/engine/narrative/types.js +1 -1
- package/dist/esm/lib/engine/traversal/FlowchartTraverser.js +10 -11
- package/dist/esm/lib/engine/types.js +1 -1
- package/dist/esm/lib/runner/ExecutionRuntime.js +1 -1
- package/dist/esm/types/lib/builder/FlowChartBuilder.d.ts +8 -10
- package/dist/esm/types/lib/builder/types.d.ts +0 -6
- package/dist/esm/types/lib/engine/graph/StageNode.d.ts +0 -2
- package/dist/esm/types/lib/engine/narrative/ControlFlowNarrativeGenerator.d.ts +6 -6
- package/dist/esm/types/lib/engine/narrative/types.d.ts +6 -6
- package/dist/esm/types/lib/engine/types.d.ts +0 -1
- package/dist/esm/types/lib/runner/ExecutionRuntime.d.ts +0 -1
- package/dist/lib/builder/FlowChartBuilder.js +54 -91
- package/dist/lib/builder/types.js +1 -1
- package/dist/lib/engine/graph/StageNode.js +1 -1
- package/dist/lib/engine/handlers/ChildrenExecutor.js +5 -5
- package/dist/lib/engine/handlers/ContinuationResolver.js +6 -6
- package/dist/lib/engine/handlers/DeciderHandler.js +4 -4
- package/dist/lib/engine/handlers/NodeResolver.js +1 -2
- package/dist/lib/engine/handlers/RuntimeStructureManager.js +1 -2
- package/dist/lib/engine/handlers/SelectorHandler.js +6 -6
- package/dist/lib/engine/narrative/ControlFlowNarrativeGenerator.js +13 -18
- package/dist/lib/engine/narrative/types.js +1 -1
- package/dist/lib/engine/traversal/FlowchartTraverser.js +10 -11
- package/dist/lib/engine/types.js +1 -1
- package/dist/lib/runner/ExecutionRuntime.js +1 -1
- package/dist/types/lib/builder/FlowChartBuilder.d.ts +8 -10
- package/dist/types/lib/builder/types.d.ts +0 -6
- package/dist/types/lib/engine/graph/StageNode.d.ts +0 -2
- package/dist/types/lib/engine/narrative/ControlFlowNarrativeGenerator.d.ts +6 -6
- package/dist/types/lib/engine/narrative/types.d.ts +6 -6
- package/dist/types/lib/engine/types.d.ts +0 -1
- package/dist/types/lib/runner/ExecutionRuntime.d.ts +0 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,9 +21,48 @@ FootPrint is a runtime for building **flowchart pipelines** where each node is j
|
|
|
21
21
|
npm install footprintjs
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { flowChart, FlowChartExecutor, ScopeFacade, toScopeFactory } from 'footprintjs';
|
|
28
|
+
|
|
29
|
+
const chart = flowChart('Greet', (scope) => {
|
|
30
|
+
scope.setValue('name', 'Alice');
|
|
31
|
+
})
|
|
32
|
+
.addFunction('Personalize', (scope) => {
|
|
33
|
+
const name = scope.getValue('name');
|
|
34
|
+
scope.setValue('message', `Hello, ${name}!`);
|
|
35
|
+
})
|
|
36
|
+
.setEnableNarrative()
|
|
37
|
+
.build();
|
|
38
|
+
|
|
39
|
+
const executor = new FlowChartExecutor(chart, toScopeFactory(ScopeFacade));
|
|
40
|
+
const result = await executor.run();
|
|
41
|
+
|
|
42
|
+
console.log(executor.getNarrative());
|
|
43
|
+
// Stage 1: The process began with Greet.
|
|
44
|
+
// Step 1: Write name = "Alice"
|
|
45
|
+
// Stage 2: Next, it moved on to Personalize.
|
|
46
|
+
// Step 1: Read name = "Alice"
|
|
47
|
+
// Step 2: Write message = "Hello, Alice!"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
> **[Try it in the browser](https://footprintjs.github.io/footprint-playground/)** — no install needed
|
|
51
|
+
>
|
|
52
|
+
> **[Browse 20+ examples](https://github.com/footprintjs/footPrint-samples)** — features, flowchart patterns, and a full loan underwriting demo
|
|
53
|
+
|
|
24
54
|
---
|
|
25
55
|
|
|
26
|
-
## Why
|
|
56
|
+
## Why FootPrint?
|
|
57
|
+
|
|
58
|
+
| | Without FootPrint | With FootPrint |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| **LLM explains a decision** | Reconstruct from scattered logs; expensive, slow, hallucination-prone | Read the causal trace; cheap model, fewer tokens, zero hallucination |
|
|
61
|
+
| **Tool descriptions** | Write and maintain them by hand | Auto-generated from the flowchart structure |
|
|
62
|
+
| **Debugging** | `console.log` + guesswork | Time-travel replay to any stage |
|
|
63
|
+
| **State management** | Global/manual, race-prone | Transactional scope with atomic commits |
|
|
64
|
+
|
|
65
|
+
### Example: Loan rejection
|
|
27
66
|
|
|
28
67
|
A loan application pipeline rejects Bob. The user asks: **"Why was I rejected?"**
|
|
29
68
|
|
|
@@ -69,86 +108,81 @@ No one wrote those trace sentences. Stage functions just read and write scope &m
|
|
|
69
108
|
|
|
70
109
|
```typescript
|
|
71
110
|
import {
|
|
72
|
-
|
|
111
|
+
flowChart, FlowChartExecutor, ScopeFacade, toScopeFactory,
|
|
73
112
|
} from 'footprintjs';
|
|
74
113
|
|
|
75
|
-
// ──
|
|
76
|
-
|
|
77
|
-
const app = {
|
|
78
|
-
applicantName: 'Bob',
|
|
79
|
-
annualIncome: 42_000,
|
|
80
|
-
monthlyDebts: 2_100,
|
|
81
|
-
creditScore: 580,
|
|
82
|
-
employmentType: 'self-employed',
|
|
83
|
-
employmentYears: 1,
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
// ── Stage functions: just do the work, no descriptions needed ──────────
|
|
114
|
+
// ── Stage functions: just read and write scope ─────────────────────────
|
|
87
115
|
|
|
88
116
|
const receiveApplication = (scope: ScopeFacade) => {
|
|
89
|
-
scope.setValue('app',
|
|
117
|
+
scope.setValue('app', {
|
|
118
|
+
applicantName: 'Bob',
|
|
119
|
+
annualIncome: 42_000,
|
|
120
|
+
monthlyDebts: 2_100,
|
|
121
|
+
creditScore: 580,
|
|
122
|
+
employmentType: 'self-employed',
|
|
123
|
+
employmentYears: 1,
|
|
124
|
+
});
|
|
90
125
|
};
|
|
91
126
|
|
|
92
127
|
const pullCreditReport = (scope: ScopeFacade) => {
|
|
93
128
|
const { creditScore } = scope.getValue('app') as any;
|
|
94
|
-
const tier = creditScore >= 740 ? 'excellent'
|
|
95
|
-
|
|
129
|
+
const tier = creditScore >= 740 ? 'excellent'
|
|
130
|
+
: creditScore >= 670 ? 'good'
|
|
131
|
+
: creditScore >= 580 ? 'fair' : 'poor';
|
|
132
|
+
|
|
96
133
|
scope.setValue('creditTier', tier);
|
|
97
134
|
scope.setValue('creditFlags', tier === 'fair' ? ['below-average credit'] : []);
|
|
98
135
|
};
|
|
99
136
|
|
|
100
137
|
const calculateDTI = (scope: ScopeFacade) => {
|
|
101
138
|
const { annualIncome, monthlyDebts } = scope.getValue('app') as any;
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
scope.setValue('
|
|
105
|
-
scope.setValue('
|
|
106
|
-
scope.setValue('dtiFlags',
|
|
107
|
-
dtiRatio > 0.43 ? [`DTI at ${Math.round(dtiRatio * 100)}% exceeds 43%`] : []);
|
|
139
|
+
const ratio = Math.round((monthlyDebts / (annualIncome / 12)) * 100) / 100;
|
|
140
|
+
|
|
141
|
+
scope.setValue('dtiRatio', ratio);
|
|
142
|
+
scope.setValue('dtiFlags', ratio > 0.43 ? [`DTI at ${Math.round(ratio * 100)}% exceeds 43%`] : []);
|
|
108
143
|
};
|
|
109
144
|
|
|
110
145
|
const verifyEmployment = (scope: ScopeFacade) => {
|
|
111
146
|
const { employmentType, employmentYears } = scope.getValue('app') as any;
|
|
112
147
|
const verified = employmentType !== 'self-employed' || employmentYears >= 2;
|
|
148
|
+
|
|
113
149
|
scope.setValue('employmentVerified', verified);
|
|
114
|
-
scope.setValue('employmentFlags',
|
|
115
|
-
|
|
150
|
+
scope.setValue('employmentFlags', !verified
|
|
151
|
+
? [`${employmentType}, ${employmentYears}yr < 2yr minimum`] : []);
|
|
116
152
|
};
|
|
117
153
|
|
|
118
154
|
const assessRisk = (scope: ScopeFacade) => {
|
|
119
|
-
const
|
|
120
|
-
const
|
|
155
|
+
const tier = scope.getValue('creditTier') as string;
|
|
156
|
+
const ratio = scope.getValue('dtiRatio') as number;
|
|
121
157
|
const verified = scope.getValue('employmentVerified') as boolean;
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
scope.setValue('riskTier', riskTier);
|
|
125
|
-
scope.setValue('riskFactors', [/* collected flags */]);
|
|
158
|
+
|
|
159
|
+
scope.setValue('riskTier', (!verified || ratio > 0.43 || tier === 'poor') ? 'high' : 'low');
|
|
126
160
|
};
|
|
127
161
|
|
|
162
|
+
// Deciders return a branch ID — the only stage that needs a return value
|
|
128
163
|
const loanDecider = (scope: ScopeFacade): string => {
|
|
129
164
|
const tier = scope.getValue('riskTier') as string;
|
|
130
|
-
|
|
165
|
+
if (tier === 'low') return 'approved';
|
|
166
|
+
if (tier === 'high') return 'rejected';
|
|
167
|
+
return 'manual-review';
|
|
131
168
|
};
|
|
132
169
|
|
|
133
|
-
// ── Build
|
|
170
|
+
// ── Build → Run → Narrative (D3-style chaining) ──────────────────────
|
|
134
171
|
|
|
135
|
-
const chart =
|
|
172
|
+
const chart = flowChart('ReceiveApplication', receiveApplication)
|
|
136
173
|
.setEnableNarrative()
|
|
137
|
-
.start('ReceiveApplication', receiveApplication)
|
|
138
174
|
.addFunction('PullCreditReport', pullCreditReport)
|
|
139
175
|
.addFunction('CalculateDTI', calculateDTI)
|
|
140
176
|
.addFunction('VerifyEmployment', verifyEmployment)
|
|
141
177
|
.addFunction('AssessRisk', assessRisk)
|
|
142
178
|
.addDeciderFunction('LoanDecision', loanDecider as any)
|
|
143
|
-
.addFunctionBranch('approved', '
|
|
144
|
-
.addFunctionBranch('rejected', '
|
|
179
|
+
.addFunctionBranch('approved', 'Approve', () => {})
|
|
180
|
+
.addFunctionBranch('rejected', 'Reject', () => {})
|
|
145
181
|
.addFunctionBranch('manual-review', 'ManualReview', () => {})
|
|
146
182
|
.setDefault('manual-review')
|
|
147
183
|
.end()
|
|
148
184
|
.build();
|
|
149
185
|
|
|
150
|
-
// ── Run and get the narrative ──────────────────────────────────────────
|
|
151
|
-
|
|
152
186
|
const executor = new FlowChartExecutor(chart, toScopeFactory(ScopeFacade));
|
|
153
187
|
await executor.run();
|
|
154
188
|
|