footprintjs 0.2.1 → 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 +85 -32
  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,67 +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
- // ── Stage functions: just do the work, no descriptions needed ──────────
76
-
77
- const receiveApplication = async (scope: ScopeFacade) => {
78
- scope.setValue('app', app); // objects, arrays, nested — all supported
114
+ // ── Stage functions: just read and write scope ─────────────────────────
115
+
116
+ const receiveApplication = (scope: ScopeFacade) => {
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
+ });
79
125
  };
80
126
 
81
- const pullCreditReport = async (scope: ScopeFacade) => {
127
+ const pullCreditReport = (scope: ScopeFacade) => {
82
128
  const { creditScore } = scope.getValue('app') as any;
83
- const tier = creditScore >= 740 ? 'excellent' : creditScore >= 670 ? 'good'
84
- : creditScore >= 580 ? 'fair' : 'poor';
129
+ const tier = creditScore >= 740 ? 'excellent'
130
+ : creditScore >= 670 ? 'good'
131
+ : creditScore >= 580 ? 'fair' : 'poor';
132
+
85
133
  scope.setValue('creditTier', tier);
86
134
  scope.setValue('creditFlags', tier === 'fair' ? ['below-average credit'] : []);
87
135
  };
88
136
 
89
- const calculateDTI = async (scope: ScopeFacade) => {
137
+ const calculateDTI = (scope: ScopeFacade) => {
90
138
  const { annualIncome, monthlyDebts } = scope.getValue('app') as any;
91
- const dtiRatio = Math.round((monthlyDebts / (annualIncome / 12)) * 100) / 100;
92
- scope.setValue('dtiRatio', dtiRatio);
93
- scope.setValue('dtiPercent', Math.round(dtiRatio * 100));
94
- scope.setValue('dtiStatus', dtiRatio > 0.43 ? 'excessive' : 'healthy');
95
- scope.setValue('dtiFlags',
96
- 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%`] : []);
97
143
  };
98
144
 
99
- const assessRisk = async (scope: ScopeFacade) => {
100
- const creditTier = scope.getValue('creditTier') as string;
101
- const dtiStatus = scope.getValue('dtiStatus') as string;
145
+ const verifyEmployment = (scope: ScopeFacade) => {
146
+ const { employmentType, employmentYears } = scope.getValue('app') as any;
147
+ const verified = employmentType !== 'self-employed' || employmentYears >= 2;
148
+
149
+ scope.setValue('employmentVerified', verified);
150
+ scope.setValue('employmentFlags', !verified
151
+ ? [`${employmentType}, ${employmentYears}yr < 2yr minimum`] : []);
152
+ };
153
+
154
+ const assessRisk = (scope: ScopeFacade) => {
155
+ const tier = scope.getValue('creditTier') as string;
156
+ const ratio = scope.getValue('dtiRatio') as number;
102
157
  const verified = scope.getValue('employmentVerified') as boolean;
103
- const riskTier = (!verified || dtiStatus === 'excessive' || creditTier === 'poor')
104
- ? 'high' : 'low';
105
- scope.setValue('riskTier', riskTier);
106
- scope.setValue('riskFactors', [/* collected flags */]);
158
+
159
+ scope.setValue('riskTier', (!verified || ratio > 0.43 || tier === 'poor') ? 'high' : 'low');
107
160
  };
108
161
 
162
+ // Deciders return a branch ID — the only stage that needs a return value
109
163
  const loanDecider = (scope: ScopeFacade): string => {
110
164
  const tier = scope.getValue('riskTier') as string;
111
- 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';
112
168
  };
113
169
 
114
- // ── Build the flow ─────────────────────────────────────────────────────
170
+ // ── Build Run → Narrative (D3-style chaining) ──────────────────────
115
171
 
116
- const chart = new FlowChartBuilder()
172
+ const chart = flowChart('ReceiveApplication', receiveApplication)
117
173
  .setEnableNarrative()
118
- .start('ReceiveApplication', receiveApplication)
119
174
  .addFunction('PullCreditReport', pullCreditReport)
120
175
  .addFunction('CalculateDTI', calculateDTI)
121
176
  .addFunction('VerifyEmployment', verifyEmployment)
122
177
  .addFunction('AssessRisk', assessRisk)
123
178
  .addDeciderFunction('LoanDecision', loanDecider as any)
124
- .addFunctionBranch('approved', 'ApproveApplication', approveFn)
125
- .addFunctionBranch('rejected', 'RejectApplication', rejectFn)
126
- .addFunctionBranch('manual-review', 'ManualReview', reviewFn)
179
+ .addFunctionBranch('approved', 'Approve', () => {})
180
+ .addFunctionBranch('rejected', 'Reject', () => {})
181
+ .addFunctionBranch('manual-review', 'ManualReview', () => {})
127
182
  .setDefault('manual-review')
128
183
  .end()
129
184
  .build();
130
185
 
131
- // ── Run and get the narrative ──────────────────────────────────────────
132
-
133
186
  const executor = new FlowChartExecutor(chart, toScopeFactory(ScopeFacade));
134
187
  await executor.run();
135
188