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.
Files changed (44) hide show
  1. package/README.md +73 -39
  2. package/dist/esm/lib/builder/FlowChartBuilder.js +54 -91
  3. package/dist/esm/lib/builder/types.js +1 -1
  4. package/dist/esm/lib/engine/graph/StageNode.js +1 -1
  5. package/dist/esm/lib/engine/handlers/ChildrenExecutor.js +5 -5
  6. package/dist/esm/lib/engine/handlers/ContinuationResolver.js +6 -6
  7. package/dist/esm/lib/engine/handlers/DeciderHandler.js +4 -4
  8. package/dist/esm/lib/engine/handlers/NodeResolver.js +1 -2
  9. package/dist/esm/lib/engine/handlers/RuntimeStructureManager.js +1 -2
  10. package/dist/esm/lib/engine/handlers/SelectorHandler.js +6 -6
  11. package/dist/esm/lib/engine/narrative/ControlFlowNarrativeGenerator.js +13 -18
  12. package/dist/esm/lib/engine/narrative/types.js +1 -1
  13. package/dist/esm/lib/engine/traversal/FlowchartTraverser.js +10 -11
  14. package/dist/esm/lib/engine/types.js +1 -1
  15. package/dist/esm/lib/runner/ExecutionRuntime.js +1 -1
  16. package/dist/esm/types/lib/builder/FlowChartBuilder.d.ts +8 -10
  17. package/dist/esm/types/lib/builder/types.d.ts +0 -6
  18. package/dist/esm/types/lib/engine/graph/StageNode.d.ts +0 -2
  19. package/dist/esm/types/lib/engine/narrative/ControlFlowNarrativeGenerator.d.ts +6 -6
  20. package/dist/esm/types/lib/engine/narrative/types.d.ts +6 -6
  21. package/dist/esm/types/lib/engine/types.d.ts +0 -1
  22. package/dist/esm/types/lib/runner/ExecutionRuntime.d.ts +0 -1
  23. package/dist/lib/builder/FlowChartBuilder.js +54 -91
  24. package/dist/lib/builder/types.js +1 -1
  25. package/dist/lib/engine/graph/StageNode.js +1 -1
  26. package/dist/lib/engine/handlers/ChildrenExecutor.js +5 -5
  27. package/dist/lib/engine/handlers/ContinuationResolver.js +6 -6
  28. package/dist/lib/engine/handlers/DeciderHandler.js +4 -4
  29. package/dist/lib/engine/handlers/NodeResolver.js +1 -2
  30. package/dist/lib/engine/handlers/RuntimeStructureManager.js +1 -2
  31. package/dist/lib/engine/handlers/SelectorHandler.js +6 -6
  32. package/dist/lib/engine/narrative/ControlFlowNarrativeGenerator.js +13 -18
  33. package/dist/lib/engine/narrative/types.js +1 -1
  34. package/dist/lib/engine/traversal/FlowchartTraverser.js +10 -11
  35. package/dist/lib/engine/types.js +1 -1
  36. package/dist/lib/runner/ExecutionRuntime.js +1 -1
  37. package/dist/types/lib/builder/FlowChartBuilder.d.ts +8 -10
  38. package/dist/types/lib/builder/types.d.ts +0 -6
  39. package/dist/types/lib/engine/graph/StageNode.d.ts +0 -2
  40. package/dist/types/lib/engine/narrative/ControlFlowNarrativeGenerator.d.ts +6 -6
  41. package/dist/types/lib/engine/narrative/types.d.ts +6 -6
  42. package/dist/types/lib/engine/types.d.ts +0 -1
  43. package/dist/types/lib/runner/ExecutionRuntime.d.ts +0 -1
  44. 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 causal traces?
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
- FlowChartBuilder, FlowChartExecutor, ScopeFacade, toScopeFactory,
111
+ flowChart, FlowChartExecutor, ScopeFacade, toScopeFactory,
73
112
  } from 'footprintjs';
74
113
 
75
- // ── The application data ──────────────────────────────────────────────
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', 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' : creditScore >= 670 ? 'good'
95
- : creditScore >= 580 ? 'fair' : 'poor';
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 dtiRatio = Math.round((monthlyDebts / (annualIncome / 12)) * 100) / 100;
103
- scope.setValue('dtiRatio', dtiRatio);
104
- scope.setValue('dtiPercent', Math.round(dtiRatio * 100));
105
- scope.setValue('dtiStatus', dtiRatio > 0.43 ? 'excessive' : 'healthy');
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
- !verified ? [`${employmentType}, ${employmentYears}yr < 2yr minimum`] : []);
150
+ scope.setValue('employmentFlags', !verified
151
+ ? [`${employmentType}, ${employmentYears}yr < 2yr minimum`] : []);
116
152
  };
117
153
 
118
154
  const assessRisk = (scope: ScopeFacade) => {
119
- const creditTier = scope.getValue('creditTier') as string;
120
- const dtiStatus = scope.getValue('dtiStatus') as string;
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
- const riskTier = (!verified || dtiStatus === 'excessive' || creditTier === 'poor')
123
- ? 'high' : 'low';
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
- return tier === 'low' ? 'approved' : tier === 'high' ? 'rejected' : 'manual-review';
165
+ if (tier === 'low') return 'approved';
166
+ if (tier === 'high') return 'rejected';
167
+ return 'manual-review';
131
168
  };
132
169
 
133
- // ── Build the flow ─────────────────────────────────────────────────────
170
+ // ── Build Run → Narrative (D3-style chaining) ──────────────────────
134
171
 
135
- const chart = new FlowChartBuilder()
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', 'ApproveApplication', () => {})
144
- .addFunctionBranch('rejected', 'RejectApplication', () => {})
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