agentfootprint 2.3.0 → 2.5.0

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 (212) hide show
  1. package/README.md +293 -247
  2. package/dist/adapters/llm/AnthropicProvider.js +2 -2
  3. package/dist/adapters/llm/AnthropicProvider.js.map +1 -1
  4. package/dist/adapters/llm/BedrockProvider.js +2 -2
  5. package/dist/adapters/llm/BedrockProvider.js.map +1 -1
  6. package/dist/adapters/llm/BrowserAnthropicProvider.js +96 -28
  7. package/dist/adapters/llm/BrowserAnthropicProvider.js.map +1 -1
  8. package/dist/adapters/llm/OpenAIProvider.js +2 -2
  9. package/dist/adapters/llm/OpenAIProvider.js.map +1 -1
  10. package/dist/adapters/memory/agentcore.js +9 -3
  11. package/dist/adapters/memory/agentcore.js.map +1 -1
  12. package/dist/adapters/memory/redis.js +9 -3
  13. package/dist/adapters/memory/redis.js.map +1 -1
  14. package/dist/core/Agent.js +493 -79
  15. package/dist/core/Agent.js.map +1 -1
  16. package/dist/core/flowchartAsTool.js +188 -0
  17. package/dist/core/flowchartAsTool.js.map +1 -0
  18. package/dist/core/outputSchema.js +119 -0
  19. package/dist/core/outputSchema.js.map +1 -0
  20. package/dist/core/slots/buildSystemPromptSlot.js +8 -0
  21. package/dist/core/slots/buildSystemPromptSlot.js.map +1 -1
  22. package/dist/core/slots/buildToolsSlot.js +56 -5
  23. package/dist/core/slots/buildToolsSlot.js.map +1 -1
  24. package/dist/esm/adapters/llm/AnthropicProvider.js +2 -2
  25. package/dist/esm/adapters/llm/AnthropicProvider.js.map +1 -1
  26. package/dist/esm/adapters/llm/BedrockProvider.js +2 -2
  27. package/dist/esm/adapters/llm/BedrockProvider.js.map +1 -1
  28. package/dist/esm/adapters/llm/BrowserAnthropicProvider.js +96 -28
  29. package/dist/esm/adapters/llm/BrowserAnthropicProvider.js.map +1 -1
  30. package/dist/esm/adapters/llm/OpenAIProvider.js +2 -2
  31. package/dist/esm/adapters/llm/OpenAIProvider.js.map +1 -1
  32. package/dist/esm/adapters/memory/agentcore.js +9 -3
  33. package/dist/esm/adapters/memory/agentcore.js.map +1 -1
  34. package/dist/esm/adapters/memory/redis.js +9 -3
  35. package/dist/esm/adapters/memory/redis.js.map +1 -1
  36. package/dist/esm/core/Agent.js +492 -78
  37. package/dist/esm/core/Agent.js.map +1 -1
  38. package/dist/esm/core/flowchartAsTool.js +184 -0
  39. package/dist/esm/core/flowchartAsTool.js.map +1 -0
  40. package/dist/esm/core/outputSchema.js +113 -0
  41. package/dist/esm/core/outputSchema.js.map +1 -0
  42. package/dist/esm/core/slots/buildSystemPromptSlot.js +8 -0
  43. package/dist/esm/core/slots/buildSystemPromptSlot.js.map +1 -1
  44. package/dist/esm/core/slots/buildToolsSlot.js +56 -5
  45. package/dist/esm/core/slots/buildToolsSlot.js.map +1 -1
  46. package/dist/esm/index.js +34 -5
  47. package/dist/esm/index.js.map +1 -1
  48. package/dist/esm/lib/injection-engine/SkillRegistry.js +181 -0
  49. package/dist/esm/lib/injection-engine/SkillRegistry.js.map +1 -0
  50. package/dist/esm/lib/injection-engine/factories/defineSkill.js +35 -0
  51. package/dist/esm/lib/injection-engine/factories/defineSkill.js.map +1 -1
  52. package/dist/esm/lib/injection-engine/index.js +9 -1
  53. package/dist/esm/lib/injection-engine/index.js.map +1 -1
  54. package/dist/esm/lib/injection-engine/skillTools.js +125 -0
  55. package/dist/esm/lib/injection-engine/skillTools.js.map +1 -0
  56. package/dist/esm/lib/injection-engine/types.js +8 -0
  57. package/dist/esm/lib/injection-engine/types.js.map +1 -1
  58. package/dist/esm/lib/lazyRequire.js +33 -0
  59. package/dist/esm/lib/lazyRequire.js.map +1 -0
  60. package/dist/esm/lib/mcp/mcpClient.js +4 -6
  61. package/dist/esm/lib/mcp/mcpClient.js.map +1 -1
  62. package/dist/esm/llm-providers.js +31 -0
  63. package/dist/esm/llm-providers.js.map +1 -0
  64. package/dist/esm/locales/index.js +144 -0
  65. package/dist/esm/locales/index.js.map +1 -0
  66. package/dist/esm/memory-providers.js +44 -0
  67. package/dist/esm/memory-providers.js.map +1 -0
  68. package/dist/esm/providers.js +11 -0
  69. package/dist/esm/providers.js.map +1 -1
  70. package/dist/esm/recorders/core/contextEngineering.js +155 -0
  71. package/dist/esm/recorders/core/contextEngineering.js.map +1 -0
  72. package/dist/esm/recorders/observability/commentary/commentaryTemplates.js +6 -1
  73. package/dist/esm/recorders/observability/commentary/commentaryTemplates.js.map +1 -1
  74. package/dist/esm/security/PermissionPolicy.js +135 -0
  75. package/dist/esm/security/PermissionPolicy.js.map +1 -0
  76. package/dist/esm/security/index.js +38 -0
  77. package/dist/esm/security/index.js.map +1 -0
  78. package/dist/esm/tool-providers/gatedTools.js +52 -0
  79. package/dist/esm/tool-providers/gatedTools.js.map +1 -0
  80. package/dist/esm/tool-providers/index.js +43 -0
  81. package/dist/esm/tool-providers/index.js.map +1 -0
  82. package/dist/esm/tool-providers/skillScopedTools.js +63 -0
  83. package/dist/esm/tool-providers/skillScopedTools.js.map +1 -0
  84. package/dist/esm/tool-providers/staticTools.js +33 -0
  85. package/dist/esm/tool-providers/staticTools.js.map +1 -0
  86. package/dist/esm/tool-providers/types.js +53 -0
  87. package/dist/esm/tool-providers/types.js.map +1 -0
  88. package/dist/index.js +57 -12
  89. package/dist/index.js.map +1 -1
  90. package/dist/lib/injection-engine/SkillRegistry.js +185 -0
  91. package/dist/lib/injection-engine/SkillRegistry.js.map +1 -0
  92. package/dist/lib/injection-engine/factories/defineSkill.js +37 -1
  93. package/dist/lib/injection-engine/factories/defineSkill.js.map +1 -1
  94. package/dist/lib/injection-engine/index.js +14 -1
  95. package/dist/lib/injection-engine/index.js.map +1 -1
  96. package/dist/lib/injection-engine/skillTools.js +130 -0
  97. package/dist/lib/injection-engine/skillTools.js.map +1 -0
  98. package/dist/lib/injection-engine/types.js +8 -0
  99. package/dist/lib/injection-engine/types.js.map +1 -1
  100. package/dist/lib/lazyRequire.js +37 -0
  101. package/dist/lib/lazyRequire.js.map +1 -0
  102. package/dist/lib/mcp/mcpClient.js +4 -6
  103. package/dist/lib/mcp/mcpClient.js.map +1 -1
  104. package/dist/llm-providers.js +47 -0
  105. package/dist/llm-providers.js.map +1 -0
  106. package/dist/locales/index.js +149 -0
  107. package/dist/locales/index.js.map +1 -0
  108. package/dist/memory-providers.js +49 -0
  109. package/dist/memory-providers.js.map +1 -0
  110. package/dist/providers.js +11 -0
  111. package/dist/providers.js.map +1 -1
  112. package/dist/recorders/core/contextEngineering.js +161 -0
  113. package/dist/recorders/core/contextEngineering.js.map +1 -0
  114. package/dist/recorders/observability/commentary/commentaryTemplates.js +6 -1
  115. package/dist/recorders/observability/commentary/commentaryTemplates.js.map +1 -1
  116. package/dist/security/PermissionPolicy.js +139 -0
  117. package/dist/security/PermissionPolicy.js.map +1 -0
  118. package/dist/security/index.js +42 -0
  119. package/dist/security/index.js.map +1 -0
  120. package/dist/tool-providers/gatedTools.js +56 -0
  121. package/dist/tool-providers/gatedTools.js.map +1 -0
  122. package/dist/tool-providers/index.js +51 -0
  123. package/dist/tool-providers/index.js.map +1 -0
  124. package/dist/tool-providers/skillScopedTools.js +67 -0
  125. package/dist/tool-providers/skillScopedTools.js.map +1 -0
  126. package/dist/tool-providers/staticTools.js +37 -0
  127. package/dist/tool-providers/staticTools.js.map +1 -0
  128. package/dist/tool-providers/types.js +54 -0
  129. package/dist/tool-providers/types.js.map +1 -0
  130. package/dist/types/adapters/llm/AnthropicProvider.d.ts.map +1 -1
  131. package/dist/types/adapters/llm/BedrockProvider.d.ts.map +1 -1
  132. package/dist/types/adapters/llm/BrowserAnthropicProvider.d.ts.map +1 -1
  133. package/dist/types/adapters/llm/OpenAIProvider.d.ts.map +1 -1
  134. package/dist/types/adapters/memory/agentcore.d.ts +7 -1
  135. package/dist/types/adapters/memory/agentcore.d.ts.map +1 -1
  136. package/dist/types/adapters/memory/redis.d.ts +7 -1
  137. package/dist/types/adapters/memory/redis.d.ts.map +1 -1
  138. package/dist/types/core/Agent.d.ts +216 -2
  139. package/dist/types/core/Agent.d.ts.map +1 -1
  140. package/dist/types/core/flowchartAsTool.d.ts +161 -0
  141. package/dist/types/core/flowchartAsTool.d.ts.map +1 -0
  142. package/dist/types/core/outputSchema.d.ts +128 -0
  143. package/dist/types/core/outputSchema.d.ts.map +1 -0
  144. package/dist/types/core/slots/buildSystemPromptSlot.d.ts.map +1 -1
  145. package/dist/types/core/slots/buildToolsSlot.d.ts +10 -0
  146. package/dist/types/core/slots/buildToolsSlot.d.ts.map +1 -1
  147. package/dist/types/index.d.ts +8 -4
  148. package/dist/types/index.d.ts.map +1 -1
  149. package/dist/types/lib/injection-engine/SkillRegistry.d.ts +148 -0
  150. package/dist/types/lib/injection-engine/SkillRegistry.d.ts.map +1 -0
  151. package/dist/types/lib/injection-engine/factories/defineSkill.d.ts +99 -0
  152. package/dist/types/lib/injection-engine/factories/defineSkill.d.ts.map +1 -1
  153. package/dist/types/lib/injection-engine/index.d.ts +5 -2
  154. package/dist/types/lib/injection-engine/index.d.ts.map +1 -1
  155. package/dist/types/lib/injection-engine/skillTools.d.ts +73 -0
  156. package/dist/types/lib/injection-engine/skillTools.d.ts.map +1 -0
  157. package/dist/types/lib/injection-engine/types.d.ts +28 -0
  158. package/dist/types/lib/injection-engine/types.d.ts.map +1 -1
  159. package/dist/types/lib/lazyRequire.d.ts +30 -0
  160. package/dist/types/lib/lazyRequire.d.ts.map +1 -0
  161. package/dist/types/lib/mcp/mcpClient.d.ts.map +1 -1
  162. package/dist/types/llm-providers.d.ts +31 -0
  163. package/dist/types/llm-providers.d.ts.map +1 -0
  164. package/dist/types/locales/index.d.ts +133 -0
  165. package/dist/types/locales/index.d.ts.map +1 -0
  166. package/dist/types/memory-providers.d.ts +41 -0
  167. package/dist/types/memory-providers.d.ts.map +1 -0
  168. package/dist/types/providers.d.ts +11 -0
  169. package/dist/types/providers.d.ts.map +1 -1
  170. package/dist/types/recorders/core/contextEngineering.d.ts +137 -0
  171. package/dist/types/recorders/core/contextEngineering.d.ts.map +1 -0
  172. package/dist/types/recorders/observability/commentary/commentaryTemplates.d.ts.map +1 -1
  173. package/dist/types/security/PermissionPolicy.d.ts +125 -0
  174. package/dist/types/security/PermissionPolicy.d.ts.map +1 -0
  175. package/dist/types/security/index.d.ts +40 -0
  176. package/dist/types/security/index.d.ts.map +1 -0
  177. package/dist/types/tool-providers/gatedTools.d.ts +37 -0
  178. package/dist/types/tool-providers/gatedTools.d.ts.map +1 -0
  179. package/dist/types/tool-providers/index.d.ts +42 -0
  180. package/dist/types/tool-providers/index.d.ts.map +1 -0
  181. package/dist/types/tool-providers/skillScopedTools.d.ts +46 -0
  182. package/dist/types/tool-providers/skillScopedTools.d.ts.map +1 -0
  183. package/dist/types/tool-providers/staticTools.d.ts +22 -0
  184. package/dist/types/tool-providers/staticTools.d.ts.map +1 -0
  185. package/dist/types/tool-providers/types.d.ts +103 -0
  186. package/dist/types/tool-providers/types.d.ts.map +1 -0
  187. package/package.json +62 -9
  188. package/README.proposed.md +0 -258
  189. package/dist/instructions.js +0 -21
  190. package/dist/instructions.js.map +0 -1
  191. package/dist/lib/instructions/defineInstruction.js +0 -35
  192. package/dist/lib/instructions/defineInstruction.js.map +0 -1
  193. package/dist/lib/instructions/evaluator.js +0 -38
  194. package/dist/lib/instructions/evaluator.js.map +0 -1
  195. package/dist/lib/instructions/index.js +0 -48
  196. package/dist/lib/instructions/index.js.map +0 -1
  197. package/dist/lib/instructions/types.js +0 -22
  198. package/dist/lib/instructions/types.js.map +0 -1
  199. package/dist/memory/conversationHelpers.js +0 -39
  200. package/dist/memory/conversationHelpers.js.map +0 -1
  201. package/dist/types/instructions.d.ts +0 -5
  202. package/dist/types/instructions.d.ts.map +0 -1
  203. package/dist/types/lib/instructions/defineInstruction.d.ts +0 -22
  204. package/dist/types/lib/instructions/defineInstruction.d.ts.map +0 -1
  205. package/dist/types/lib/instructions/evaluator.d.ts +0 -11
  206. package/dist/types/lib/instructions/evaluator.d.ts.map +0 -1
  207. package/dist/types/lib/instructions/index.d.ts +0 -44
  208. package/dist/types/lib/instructions/index.d.ts.map +0 -1
  209. package/dist/types/lib/instructions/types.d.ts +0 -100
  210. package/dist/types/lib/instructions/types.d.ts.map +0 -1
  211. package/dist/types/memory/conversationHelpers.d.ts +0 -19
  212. package/dist/types/memory/conversationHelpers.d.ts.map +0 -1
package/README.md CHANGED
@@ -1,351 +1,397 @@
1
1
  <p align="center">
2
- <h1 align="center">AgentFootPrint</h1>
2
+ <h1 align="center">agentfootprint</h1>
3
3
  <p align="center">
4
- <strong>Context engineering, made buildable.</strong>
4
+ <strong>Context engineering, abstracted.</strong>
5
5
  </p>
6
6
  </p>
7
7
 
8
8
  <p align="center">
9
9
  <a href="https://github.com/footprintjs/agentfootprint/actions"><img src="https://github.com/footprintjs/agentfootprint/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
10
+ <a href="https://codecov.io/gh/footprintjs/agentfootprint"><img src="https://codecov.io/gh/footprintjs/agentfootprint/branch/main/graph/badge.svg" alt="Coverage"></a>
10
11
  <a href="https://www.npmjs.com/package/agentfootprint"><img src="https://img.shields.io/npm/v/agentfootprint.svg?style=flat" alt="npm version"></a>
11
- <a href="https://github.com/footprintjs/agentfootprint/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License"></a>
12
12
  <a href="https://www.npmjs.com/package/agentfootprint"><img src="https://img.shields.io/npm/dm/agentfootprint.svg" alt="Downloads"></a>
13
- <a href="https://footprintjs.github.io/agentfootprint/"><img src="https://img.shields.io/badge/Docs-agentfootprint-facc15?style=flat&logo=typescript&logoColor=white" alt="Docs"></a>
14
- <a href="https://github.com/footprintjs/footPrint"><img src="https://img.shields.io/badge/Built_on-footprintjs-ca8a04?style=flat" alt="Built on footprintjs"></a>
13
+ <a href="https://github.com/footprintjs/agentfootprint/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT"></a>
15
14
  </p>
16
15
 
17
16
  <br>
18
17
 
19
- **Building Generative AI applications is mostly *context engineering*** &mdash; deciding *what content lands in which slot of the LLM call, when, and why*. agentfootprint gives you a framework to build generative AI apps — single LLM calls, agents, multi-agent systems — where this discipline is **buildable at the control-flow level** (Sequence, Parallel, Conditional, Loop), not hidden inside new classes per paper.
18
+ > **PyTorch's autograd abstracted gradient computation. Express abstracted the HTTP request loop. Prisma abstracted SQL CRUD. Kubernetes abstracted reconciliation. React abstracted the DOM.**
19
+ >
20
+ > Every load-bearing dev tool of the last decade is *the same kind of move* — abstract one specific kind of bookkeeping that practitioners were doing by hand, so they can spend their attention on intent instead of plumbing.
21
+ >
22
+ > **agentfootprint is that move applied to context engineering** — the discipline of deciding what content lands in which slot of an LLM call, when, and why. You describe injections declaratively. The framework evaluates every trigger every iteration, composes the `system` / `messages` / `tools` slots, observes every decision as a typed event, and persists checkpoints you can replay six months later. So you write the **intent**, not 200 lines of slot-management bookkeeping per agent.
20
23
 
21
- ```bash
22
- npm install agentfootprint footprintjs
23
- ```
24
+ | Framework | You write declaratively | The framework abstracts |
25
+ |---|---|---|
26
+ | **PyTorch (autograd)** | Forward computation graph | Gradient computation, backward pass, parameter bookkeeping |
27
+ | **Express / Fastify** | Routes + handlers | HTTP request loop, middleware chain, response serialization |
28
+ | **Prisma / SQLAlchemy** | Schema + query intent | SQL generation, connection pooling, migrations |
29
+ | **Kubernetes** | Desired state (manifests) | Scheduling, health checks, reconciliation loop |
30
+ | **React** | Components + state | DOM diffing, render path, event delegation |
31
+ | **agentfootprint** | Injections (slot × trigger) | Slot composition, iteration loop, observation, replay |
32
+
33
+ The closest structural parallel is **autograd**: you describe the graph, the framework traverses it, and *because the framework owns the traversal it can record everything that happens for free*. Same idea here — you describe Injections, agentfootprint runs the iteration loop, and the typed-event stream + replayable checkpoints are a consequence, not an extra feature.
34
+
35
+ <!-- ┌────────────────────────────────────────────────────────────────┐
36
+ │ 📹 30-second demo video here. │
37
+ │ Embed: paste-trace → drag time-travel slider → │
38
+ │ every slot, every decision, every tool call visible. │
39
+ │ Frame this as "agent DevTools" — the React DevTools moment.│
40
+ └────────────────────────────────────────────────────────────────┘ -->
41
+
42
+ ---
43
+
44
+ ## The abstraction, concretely
45
+
46
+ ### Without agentfootprint — context engineering by hand
24
47
 
25
48
  ```typescript
26
- const agent = Agent.create({ provider: anthropic(...) })
27
- .steering(tone) // always-on persona
28
- .instruction(urgentRule) // rule-gated, fires when matched
29
- .skill(billingSkill) // LLM-activated body + tools
30
- .memory(causalMemory) // cross-run "why" replay
31
- .build();
49
+ async function runAgentTurn(userMsg, state) {
50
+ let systemPrompt = baseSystem;
51
+ const messages = [...state.history, { role: 'user', content: userMsg }];
52
+ let activeTools = [...baseTools];
53
+
54
+ // 1. Apply always-on steering rules
55
+ for (const rule of steeringRules) systemPrompt += '\n' + rule.text;
56
+
57
+ // 2. Evaluate conditional instructions
58
+ for (const inst of instructions) {
59
+ if (inst.activeWhen(state)) systemPrompt += '\n' + inst.prompt;
60
+ }
61
+
62
+ // 3. Check on-tool-return triggers
63
+ if (state.lastToolResult?.toolName === 'redact_pii') {
64
+ messages.push({ role: 'system', content: 'Use redacted text only.' });
65
+ }
66
+
67
+ // 4. Resolve LLM-activated skills
68
+ for (const id of state.activatedSkills) {
69
+ systemPrompt += '\n' + skills[id].body;
70
+ activeTools.push(...skills[id].tools);
71
+ }
72
+
73
+ // 5. Load + format memory for this tenant
74
+ const memEntries = await store.list({ tenant, conversationId });
75
+ messages.unshift({ role: 'system', content: formatMemory(memEntries.slice(-10)) });
76
+
77
+ // 6. Call LLM, route tool calls, loop, capture state for resume...
78
+ // 7. Persist new turn back to memory tagged with identity...
79
+ // 8. Wire SSE for streaming, attach observability hooks...
80
+
81
+ // No replay. No audit trail. Per agent, hundreds of lines.
82
+ // Every refactor risks a slot-ordering bug nobody catches until prod.
83
+ }
32
84
  ```
33
85
 
34
- ---
86
+ ### With agentfootprint — declarative
35
87
 
36
- ## What is context engineering?
88
+ ```typescript
89
+ const agent = Agent.create({ provider, model: 'claude-sonnet-4-5-20250929' })
90
+ .system('You are a support assistant.')
91
+ .steering(toneRule) // always-on
92
+ .instruction(urgentRule) // rule-gated
93
+ .skill(billingSkill) // LLM-activated
94
+ .memory(conversationMemory) // cross-run, multi-tenant
95
+ .tool(weather)
96
+ .build();
37
97
 
38
- Every LLM call has **three slots**:
98
+ await agent.run({ message: userInput, identity: { conversationId } });
39
99
 
40
- ```
41
- ┌──────────────────────────────────────────────────────────────┐
42
- ┌─────────────────────┐ ┌──────────────┐ ┌────────────┐ │
43
- │ │ system-prompt slot │ │ messages slot│ │ tools slot │ │
44
- │ │ (instructions, │ │ (history, │ │ (functions │ │
45
- │ │ persona, rules) │ │ user input, │ │ the LLM │ │
46
- │ │ │ │ tool results)│ │ may call) │ │
47
- │ └─────────────────────┘ └──────────────┘ └────────────┘ │
48
- └──────────────────────────────────────────────────────────────┘
100
+ // Every iteration is a replayable typed event stream — for free.
101
+ agent.on('agentfootprint.context.injected', (e) =>
102
+ console.log(`[${e.payload.source}] landed in ${e.payload.slot}`));
49
103
  ```
50
104
 
51
- Context engineering is **deciding what flows into each slot, when**. The same content can be a *Skill* (LLM activates it), a *Steering* doc (always-on), an *Instruction* (rule-gated), a *Fact* (developer-supplied data), or a *Memory* (learned across runs). They're flavors of the same idea: **injection into a slot at the right moment**.
105
+ Same agent. The hand-rolled version is ~80 lines and growing; the declarative version is ~8 and stable. **The framework owns the wiring** which is exactly why it can observe, replay, and audit it for you.
52
106
 
53
- | Flavor | Slot | When it injects |
54
- |---|---|---|
55
- | **Skill** | system-prompt + tools | When the LLM calls `read_skill('billing')` |
56
- | **Steering** | system-prompt | Always-on (persona, output format, safety) |
57
- | **Instruction** | system-prompt or messages | Rule-gated (predicate matches the turn / a tool just returned) |
58
- | **Fact** | system-prompt or messages | Always-on, but data &mdash; user profile, env, current time |
59
- | **Memory** | messages | Learned across runs &mdash; window / facts / narrative / **causal snapshots** |
60
- | **RAG** | messages | Retrieved chunks (rule + score threshold) |
107
+ ---
61
108
 
62
- You're not learning N new framework classes &mdash; you're learning **one model**: slot &times; flavor &times; timing.
109
+ ## In 30 seconds runs offline, no API key
63
110
 
64
- ---
111
+ ```bash
112
+ npm install agentfootprint footprintjs
113
+ ```
65
114
 
66
- ## Where do you inject?
115
+ ```typescript
116
+ import { Agent, defineTool, mock } from 'agentfootprint';
67
117
 
68
- Into the three slots of the LLM API call:
118
+ const weather = defineTool({
119
+ name: 'weather',
120
+ description: 'Get current weather for a city.',
121
+ inputSchema: {
122
+ type: 'object',
123
+ properties: { city: { type: 'string' } },
124
+ required: ['city'],
125
+ },
126
+ execute: async ({ city }: { city: string }) => `${city}: 72°F, sunny`,
127
+ });
69
128
 
70
- | LLM API field | Holds | Examples of what you'd inject here |
71
- |---|---|---|
72
- | **`system` prompt** | Persona, rules, available capabilities | Steering doc · Instruction text · Skill body · Fact data · formatted memory |
73
- | **`messages` array** | Conversation turns + tool results | Memory replay · RAG chunks · synthetic tool results · injected instructions on a recent turn |
74
- | **`tools` array** | Function schemas the LLM may call | Skill-attached tools · permission-gated subset · per-iteration dynamic registry |
129
+ const agent = Agent.create({
130
+ provider: mock({ reply: 'I checked: it is 72°F and sunny.' }), // ← deterministic, no API key
131
+ model: 'mock',
132
+ })
133
+ .system('You answer weather questions using the weather tool.')
134
+ .tool(weather)
135
+ .build();
75
136
 
76
- Every injection Skill, Steering, Instruction, Fact, Memory, RAG, Guardrail — lands in **one of these three places**. There is no fourth slot.
137
+ const result = await agent.run({ message: 'Weather in Paris?' });
138
+ console.log(result); // → "I checked: it is 72°F and sunny."
139
+ ```
77
140
 
78
- ## When (and how) do we inject?
141
+ Swap `mock(...)` for `anthropic(...)` / `openai(...)` / `bedrock(...)` / `ollama(...)` for production. Nothing else changes.
142
+
143
+ ---
79
144
 
80
- Context engineering happens at runtime. Three timing levels of expressiveness:
145
+ ## The mental model three slots, four triggers, one Injection
146
+
147
+ Every LLM call has three slots. **Every "agent feature" — Skill, Steering doc, Instruction, Fact, Memory replay, RAG chunk — is content flowing into one of them, under one of four triggers.** That's the entire abstraction.
81
148
 
82
149
  ```
83
- 1. LLMCall ← one-shot. Inject once before the call.
84
-
85
- 2. Agent (ReAct loop) ← inject before EVERY iteration.
86
-
87
- 3. Dynamic Agent ← inject DIFFERENTLY per iteration based on
88
- tool results, reasoning state, or user input.
150
+ ┌─────────────────────────────────────┐
151
+ │ │
152
+ │ Your LLM call has 3 slots: │
153
+ │ │
154
+ │ system messages tools │
155
+ │ ▲ ▲ ▲ │
156
+ └───────┼──────────┼──────────┼───────┘
157
+ │ │ │
158
+ │ one │ one │
159
+ │ Injection│ Injection│
160
+ │ fires… │ fires… │
161
+ │ │ │
162
+ ┌──────────────┴────┐ ┌──┴───┐ ┌──┴────┐
163
+ │ defineSteering │ │ ... │ │ ... │
164
+ │ defineInstruction │ │ │ │ │
165
+ │ defineSkill │ │ │ │ │
166
+ │ defineFact │ │ │ │ │
167
+ │ defineMemory(read) │ │ │ │ │
168
+ │ defineRAG │ │ │ │ │
169
+ │ …your next idea │ │ │ │ │
170
+ └────────────────────┘ └──────┘ └───────┘
171
+
172
+ …under one of:
173
+ always · rule · on-tool-return · llm-activated
89
174
  ```
90
175
 
91
- The third level is where context engineering pays off. The agent calls a `redact_pii` tool on the *next* iteration, an Instruction with `trigger: 'on-tool-return'` fires that says *"use the redacted text only, don't paraphrase the original"*. That kind of just-in-time injection is what separates an LLM that follows the rules from one that drifts.
176
+ There's no fourth slot. There won't be. Every named pattern in the agent literature Reflexion, Tree-of-Thoughts, Skills, RAG, Constitutional AI reduces to *which slot* + *which trigger*. **You learn one model; the field's growth lands as new factories on the same primitive.**
177
+
178
+ ### The four triggers — *who decides* this injection is needed right now?
179
+
180
+ | Trigger | Who decides | Fires when | Real-world example |
181
+ |---|---|---|---|
182
+ | `always` | nobody (always on) | Every iteration, every turn | *"Be friendly and concise."* — `defineSteering` |
183
+ | `rule` | **you**, via predicate | A `(ctx) => boolean` you wrote returns true | *"If user wrote 'urgent', prioritize fastest path."* — `defineInstruction({ activeWhen })` |
184
+ | `on-tool-return` | **the system** | A specific tool just returned (recency-first injection on the next iteration) | *"After `redact_pii` ran, use redacted text only."* — Dynamic ReAct |
185
+ | `llm-activated` | **the LLM** | The LLM called your activation tool (e.g. `read_skill('billing')`) | Skill body + unlocked tools land next iteration — `defineSkill` |
92
186
 
93
- agentfootprint handles all three timing levels through the **same** primitive (`Injection`), evaluated by the **same** engine, observed by the **same** event (`agentfootprint.context.injected`).
187
+ Why exactly four? Because *who decides activation* is a closed axis: nobody / the developer / the system / the LLM. Together those four exhaust the meaningful "when does this content matter?" cases. A fifth would require introducing a new agent of decision — and there isn't one. That's why the primitive surface stays this small even as named patterns proliferate above it.
94
188
 
95
189
  ---
96
190
 
97
- ## Building a generative app = deciding when/how to inject
191
+ ## Why this isn't just an ergonomics win Dynamic ReAct
98
192
 
99
- That's the discipline. agentfootprint abstracts it for you in two layers, both built on the [footprintjs](https://github.com/footprintjs/footPrint) flowchart substrate:
193
+ The React parallel goes one layer deeper than "less code." Because the framework owns the loop, **the framework recomposes the prompt + tool list every iteration based on what just happened.** That's what we call **Dynamic ReAct** — and it's the thing other agent frameworks don't do.
100
194
 
101
- ### Layer 1 Single agent: one `Injection` primitive
195
+ | You write declaratively | The framework does for you, **every iteration** |
196
+ |---|---|
197
+ | `.steering(rule)` | Evaluates every iteration, composes into `system` slot |
198
+ | `.instruction(activeWhen, prompt)` | Re-evaluates predicate per iteration; routes to `system` or `messages` for attention positioning |
199
+ | `.skill(billing)` | Auto-attaches `read_skill` tool; LLM activates by id; body + unlocked tools land in next iteration |
200
+ | `.memory(causal)` | Persists footprintjs decision-evidence snapshots; embeds queries; cosine-matches on follow-up runs |
201
+ | `.tool(weather)` | Schemas to LLM, dispatches calls, captures args/results, gates by permission policy |
202
+ | `.attach(recorder)` | Subscribes to 47 typed events across 13 domains as the chart traverses |
203
+ | `agent.run({...})` | Captures every decision, every commit, every tool call as a JSON checkpoint that's replayable cross-server |
102
204
 
103
- For ONE agent, every Skill / Steering / Instruction / Fact / Memory / RAG is the same `Injection` primitive: *"this content lands in this slot when this trigger matches."* You define them; the engine evaluates them per iteration; observability flows through one event.
205
+ LangChain assembles prompts once per turn. LangGraph composes state per node, not per loop iteration. CrewAI's Agent is tool-aware but not iteration-aware. **Per-iteration recomposition of all three slots based on the latest tool result + accumulated state is structurally distinct.** It's the closest a framework comes to "executive-function-like" behavior context that adapts to what the agent just observed, not just what it was originally told.
104
206
 
105
- ```
106
- Agent ─► InjectionEngine ─► ┌─ system-prompt slot ─► CallLLM ─► Tools ─► loop
107
- ├─ messages slot
108
- └─ tools slot
109
- ```
207
+ ### What "every iteration" makes possible
110
208
 
111
- ### Layer 2 Multi-agent: connect agents through control flow
209
+ Use cases that emerge once the loop re-evaluates everything:
112
210
 
113
- For MULTIPLE agents, you don't need a new primitive. Connect them with the same control-flow building blocks that connect any flowchart stages:
211
+ | Use case | The mechanism |
212
+ |---|---|
213
+ | **Tool-by-tool LLM steering** — agent called `redact_pii` → next iter, system prompt gets *"use redacted text, don't paraphrase original"* | `defineInstruction({ activeWhen: (ctx) => ctx.lastToolResult?.toolName === 'redact_pii' })` |
214
+ | **Adaptive tool exposure** — agent activated `billing` skill → next iter, tool list switches to billing-only set (3× context-budget reduction) | `defineSkill({...}) + autoActivate` (lands in v2.5+) |
215
+ | **Cost guardrails** — accumulated cost > threshold → next iter, system prompt adds *"be concise"* | `defineInstruction({ activeWhen: (ctx) => ctx.accumulatedCostUsd > 0.50 })` |
216
+ | **Iterative format refinement** — iter 1 emitted JSON → iter 2 prompt adds *"continue this format"*; iter 5 prompt drops it | predicate over `ctx.iteration` + `ctx.history` |
217
+ | **Failure adaptation** — tool X returned an error → next iter, prompt adds *"don't try X again; use Y"* | `on-tool-return` predicate inspecting `ctx.lastToolResult` for error markers |
218
+ | **Few-shot evolution** — iter 1 prompt has example for the rare case → iter 2 drops it because example is consumed | predicate that tracks which examples have already fired |
219
+ | **Skill body refresh** — long-context run, system-prompt skill body decayed → re-inject via tool result | `defineSkill({ refreshPolicy: { afterTokens: 50_000 } })` (v2.5+) |
114
220
 
115
- | Composition | What it does | Multi-agent example |
116
- |---|---|---|
117
- | **Sequence** | A → B → C | `Sequence(Researcher, Writer, Editor)` — output flows downstream |
118
- | **Parallel** | fan-out, merge | `Parallel(Critic1, Critic2, Critic3) + merge` — multi-perspective review |
119
- | **Conditional** | predicate-based routing | route to specialist Agent based on intent classification |
120
- | **Loop** | repeat with budget | `Loop(Agent + judge)` — iterate until quality bar hit |
221
+ The framework owns the loop. The framework re-evaluates triggers every iteration. Tool results reshape the next iteration's prompt. **That's what makes context engineering compositional instead of static.**
121
222
 
122
- That's it. **No `MultiAgentSystem` class. No `Orchestrator` class. No new vocabulary.** Multi-agent is just compositions of single Agents through control flow.
223
+ **The flowchart-pattern substrate** ([footprintjs](https://github.com/footprintjs/footPrint)) is what makes the observation automatic. Every stage execution is a typed event during one DFS traversal — no instrumentation, no post-processing. Same way React DevTools shows you the component tree because React owns the render path, agentfootprint shows you the slot composition because agentfootprint owns the prompt path.
123
224
 
124
- ### Same abstraction → native patterns
225
+ ---
125
226
 
126
- Because the substrate is so small (Agent + Sequence/Parallel/Conditional/Loop), every named multi-agent pattern is just a recipe — and we ship runnable examples for the canonical ones:
227
+ ## What you can build
127
228
 
128
- | Pattern | Recipe | Source |
129
- |---|---|---|
130
- | **ReAct** | `Agent` with the default loop | Yao 2022 |
131
- | **Reflexion** | `Sequence(Agent, critique-LLM, Agent)` | Shinn 2023 |
132
- | **Tree-of-Thoughts** | `Parallel(Agent × N) + rank` | Yao 2023 |
133
- | **Self-Consistency** | `Parallel(Agent × N) + majority-vote` | Wang 2022 |
134
- | **Debate** | `Loop(Agent × 2 + judge)` | Du 2023 |
135
- | **Map-Reduce** | `Parallel(Agent × N) + merge` | Dean 2004 |
136
- | **Swarm** | `Agent` whose tools are other `Agent`s | OpenAI 2024 |
229
+ Three example shapes, all runnable end-to-end with `npm run example examples/<file>.ts`.
137
230
 
138
- Browse them in [`examples/patterns/`](examples/patterns/). Every file runs end-to-end with `npm run example examples/patterns/<file>.ts`. **You compose. We don't ship a `ReflexionAgent` class.**
231
+ ### Customer support agent (skills + memory + audit trail)
139
232
 
140
- > **Show me the smallest one** — [`examples/patterns/02-reflection.ts`](examples/patterns/02-reflection.ts) implements Reflexion in ~30 lines. Run it: `npm run example examples/patterns/02-reflection.ts`.
233
+ ```typescript
234
+ const agent = Agent.create({ provider, model: 'claude-sonnet-4-5-20250929' })
235
+ .system('You are a friendly support assistant.')
236
+ .skill(billingSkill) // LLM activates with read_skill('billing')
237
+ .steering(toneGuidelines) // always-on
238
+ .memory(conversationMemory) // remembers across .run() calls, per-tenant
239
+ .build();
240
+ ```
141
241
 
142
- ---
242
+ → [`examples/context-engineering/06-mixed-flavors.ts`](examples/context-engineering/06-mixed-flavors.ts)
143
243
 
144
- ## Why a context-engineering framework
244
+ ### Research pipeline (multi-agent fan-out + merge)
145
245
 
146
- If you're going to build generative AI apps on a framework, pick the one whose **core stays small as the field grows**. agentfootprint's core has *one* Injection primitive. Every current flavor reduces to it &mdash; and so will every flavor that hasn't been invented yet.
246
+ ```typescript
247
+ const research = Parallel.create()
248
+ .branch(optimist).branch(skeptic).branch(historian)
249
+ .merge(synthesizer)
250
+ .build();
147
251
 
148
- ```
149
- Skill = Injection { trigger: 'llm-activated', slots: [system-prompt, tools] }
150
- Steering = Injection { trigger: 'always-on', slots: [system-prompt] }
151
- Instruction = Injection { trigger: 'rule', slots: [system-prompt | messages] }
152
- Fact = Injection { trigger: 'always-on', slots: [system-prompt | messages] }
153
- RAG = Injection { trigger: 'rule + score', slots: [messages] } (v2.1) ✓
154
- Guardrail = Injection { trigger: 'on-tool-return',slots: [system-prompt] } (v2.x)
155
- ??? = Injection { trigger: ?, slots: ? } (your idea)
252
+ await research.run({ message: 'Should we adopt microservices?' });
156
253
  ```
157
254
 
158
- Adding the next flavor is **one new factory file** &mdash; no engine change, no slot subflow change, no consumer-API change. Lens chips, observability events, audit trails all flow through the same plumbing.
255
+ [`examples/patterns/05-tot.ts`](examples/patterns/05-tot.ts) (Tree-of-Thoughts) · [`examples/patterns/01-self-consistency.ts`](examples/patterns/01-self-consistency.ts)
159
256
 
160
- | | Frameworks growing class-per-paper | agentfootprint |
161
- |---|---|---|
162
- | Adding a new flavor (e.g. *guardrail*) | New `GuardrailAgent` class, new event type, new UI surface | One factory file, same `Injection` shape, same `context.injected` event |
163
- | Cross-run "why was X rejected?" | LLM reconstructs from messages | Replay EXACT past decisions from causal snapshots |
164
- | Training-data export | Manual, lossy, optional | Same snapshot shape → SFT / DPO / process-RL ready (v2.1+) |
165
- | Decision evidence | Lost &mdash; only the final answer survives | First-class events from `decide()` / `select()` captured during traversal |
257
+ ### Streaming chat agent (token-by-token to a browser)
166
258
 
167
- ---
168
-
169
- ## Quick Start
259
+ <!-- ┌────────────────────────────────────────────────────────────────┐
260
+ │ 📹 Streaming demo clip here. │
261
+ │ Short loop: user types → tokens stream → tool call │
262
+ │ surfaces mid-stream → final answer. │
263
+ └────────────────────────────────────────────────────────────────┘ -->
170
264
 
171
265
  ```typescript
172
- import {
173
- Agent, defineTool, defineSteering, defineInstruction,
174
- defineMemory, MEMORY_TYPES, MEMORY_STRATEGIES,
175
- InMemoryStore, anthropic,
176
- } from 'agentfootprint';
266
+ agent.on('agentfootprint.stream.token', (e) => res.write(e.payload.content));
267
+ agent.on('agentfootprint.stream.tool_start', (e) => res.write(`\n→ ${e.payload.toolName}...\n`));
268
+ await agent.run({ message: userInput });
269
+ ```
177
270
 
178
- // Want $0 testing? Swap `anthropic({...})` for `mock({ reply: '...' })`
179
- // — same agent, same flowchart, no API key needed.
271
+ [`docs-site/guides/streaming/`](docs-site/src/content/docs/guides/streaming.mdx)
180
272
 
181
- // 1. A tool the agent can call
182
- const weather = defineTool({
183
- schema: {
184
- name: 'weather',
185
- description: 'Current weather for a city.',
186
- inputSchema: {
187
- type: 'object',
188
- properties: { city: { type: 'string' } },
189
- required: ['city'],
190
- },
191
- },
192
- execute: async (args) => `${(args as { city: string }).city}: 72°F, sunny`,
193
- });
273
+ ---
194
274
 
195
- // 2. Context engineering: one steering doc + one rule-gated instruction
196
- const tone = defineSteering({
197
- id: 'tone',
198
- prompt: 'Be friendly and concise. Acknowledge feelings before facts.',
199
- });
275
+ ## The differentiator: the trace is a cache of the agent's thinking
200
276
 
201
- const urgent = defineInstruction({
202
- id: 'urgent',
203
- activeWhen: (ctx) => /urgent|asap|emergency/i.test(ctx.userMessage),
204
- prompt: 'The user marked this urgent. Prioritize the fastest resolution.',
205
- });
277
+ Other agent frameworks' memory remembers *what was said*. agentfootprint's `defineMemory({ type: CAUSAL })` records the **decision evidence** — every value the agent's flowchart captured during the run, persisted as a JSON-portable snapshot.
206
278
 
207
- // 3. Memory across runs
208
- const memory = defineMemory({
209
- id: 'short-term',
210
- type: MEMORY_TYPES.EPISODIC,
211
- strategy: { kind: MEMORY_STRATEGIES.WINDOW, size: 10 },
212
- store: new InMemoryStore(),
213
- });
279
+ That changes the cost structure of *everything that happens after the agent runs.* The expensive thinking happened once; the recorded trace makes consuming that thinking cheap, three different ways:
214
280
 
215
- // 4. Buildevery layer composes
216
- const agent = Agent.create({
217
- provider: anthropic({ apiKey: process.env.ANTHROPIC_API_KEY! }),
218
- model: 'claude-sonnet-4-5-20250929',
219
- })
220
- .system('You are a helpful weather assistant.')
221
- .tool(weather)
222
- .steering(tone)
223
- .instruction(urgent)
224
- .memory(memory)
225
- .build();
281
+ ### 1. Audit / explain cross-run, six months later, exact past facts
226
282
 
227
- // 5. Run with multi-tenant identity
228
- const id = { conversationId: 'alice-session' };
229
- await agent.run({ message: 'Weather in SF urgently?', identity: id });
283
+ ```typescript
284
+ const causal = defineMemory({
285
+ id: 'causal',
286
+ type: MEMORY_TYPES.CAUSAL,
287
+ strategy: { kind: MEMORY_STRATEGIES.TOP_K, topK: 1, threshold: 0.7, embedder },
288
+ store,
289
+ projection: SNAPSHOT_PROJECTIONS.DECISIONS, // inject "why" only, not "what"
290
+ });
291
+
292
+ // Monday: agent decides loan #42 should be rejected (creditScore=580, threshold=600).
293
+ // Friday: user asks "Why was my application rejected?"
294
+ // → Causal memory loads the exact decision evidence from Monday.
295
+ // → LLM answers from the SOURCE, not reconstruction.
230
296
  ```
231
297
 
232
- Every `.steering` / `.instruction` / `.memory` / `.tool` call adds an injection or a binding. The Agent's flowchart shows them as visible subflows in the narrative &mdash; you can read exactly *what landed in which slot, when, and why* for any run.
298
+ [`examples/memory/06-causal-snapshot.ts`](examples/memory/06-causal-snapshot.ts) runs end-to-end with mock embedder, ~50 lines.
233
299
 
234
- ---
300
+ ### 2. Cheap-model triage — the trace *is* the reasoning
235
301
 
236
- ## Build with mocks first &mdash; swap real infra later
302
+ A trace recorded from your expensive production model (Sonnet-4, GPT-4) is a perfectly good *input* for a small, fast, cheap model (Haiku, GPT-4o-mini) answering follow-up questions about that run. The expensive model already did the work; the cheap model just **reads what's in the trace**.
237
303
 
238
- Generative AI app development is expensive when every iteration hits a paid API. agentfootprint is designed so you can **build the entire app &mdash; agent, context engineering, tool chains, memory, RAG &mdash; against in-memory mocks**, prove the logic and patterns end-to-end with zero API cost, then swap real infrastructure in piece by piece.
304
+ Reading recorded decision evidence is structurally simpler than re-deriving the answer from first principles so a smaller model is enough. You can compose the routing yourself: when causal memory injected a snapshot on the next turn, send that turn to a cheaper provider.
239
305
 
240
306
  ```typescript
241
- import {
242
- Agent, defineTool, defineSteering, defineMemory,
243
- MEMORY_TYPES, MEMORY_STRATEGIES,
244
- mock, InMemoryStore, // ← the mock surfaces
245
- } from 'agentfootprint';
307
+ const heavy = anthropic({ apiKey: process.env.ANTHROPIC_API_KEY! });
308
+ const cheap = anthropic({ apiKey: process.env.ANTHROPIC_API_KEY! });
246
309
 
247
- const agent = Agent.create({
248
- provider: mock({ reply: 'Refunds take 3 business days.' }), // ← no API key
249
- model: 'mock',
250
- })
251
- .steering(defineSteering({ id: 'tone', prompt: 'Be friendly.' }))
252
- .tool(defineTool({
253
- schema: { name: 'lookup', description: '...', inputSchema: {} },
254
- execute: async () => 'mock data', // ← inline mock
255
- }))
256
- .memory(defineMemory({
257
- id: 'short-term',
258
- type: MEMORY_TYPES.EPISODIC,
259
- strategy: { kind: MEMORY_STRATEGIES.WINDOW, size: 10 },
260
- store: new InMemoryStore(), // ← ephemeral
261
- }))
310
+ // Production turn — heavy model, full reasoning, snapshot persisted.
311
+ const productionAgent = Agent.create({ provider: heavy, model: 'claude-sonnet-4-5-20250929' })
312
+ .memory(causal)
262
313
  .build();
314
+ await productionAgent.run({ message: 'Should we approve loan #42?', identity });
263
315
 
264
- await agent.run({ message: 'How long does a refund take?' });
316
+ // Follow-up turn cheaper model reads the snapshot, lower cost per turn.
317
+ const followUpAgent = Agent.create({ provider: cheap, model: 'claude-haiku-4-5-20251001' })
318
+ .memory(causal)
319
+ .build();
320
+ await followUpAgent.run({ message: 'Why was loan #42 rejected?', identity });
265
321
  ```
266
322
 
267
- The whole flow runs offline. Iterate on context engineering, narrative, control-flow patterns, error handling, multi-agent compositions &mdash; **without** spending a cent.
323
+ This is memoization for agent reasoning do the expensive work once, serve many queries from the cached result. Across a production system that handles audit / explain / "why did the agent do X?" traffic, this is real money.
268
324
 
269
- When the logic is right, swap one boundary at a time:
325
+ ### 3. Training data every successful run becomes a labeled trajectory
270
326
 
271
- | Boundary | Mock for development | Production swap |
272
- |---|---|---|
273
- | **LLM provider** | `mock({ reply })` &middot; `mock({ replies })` for scripted ReAct | `anthropic()` &middot; `openai()` &middot; `bedrock()` &middot; `ollama()` |
274
- | **Embedder** | `mockEmbedder()` | OpenAI / Cohere / Bedrock embedder (factories on roadmap) |
275
- | **Memory store** | `InMemoryStore` | `RedisStore` (`agentfootprint/memory-redis`) &middot; `AgentCoreStore` (`agentfootprint/memory-agentcore`) &middot; DynamoDB / Postgres / Pinecone (planned) |
276
- | **MCP server** | `mockMcpClient({ tools })` &mdash; in-memory, no SDK | `mcpClient({ transport })` to a real server |
277
- | **Tool execution** | `defineTool({ execute: async () => '...' })` | Same `defineTool`, real implementation |
327
+ The same snapshot data shape is the input to SFT / DPO / process-RL training pipelines (`causalMemory.exportForTraining({ format: 'sft' | 'dpo' | 'process' })` is on the roadmap — see below). You don't run a separate data-collection phase — **your production traffic IS your training set.** Every successful customer interaction is a positive trajectory; every escalation or override is a counter-example.
278
328
 
279
- Each swap is one line. The flowchart, narrative, recorders, and tests don't change. Ship the patterns first; pay for tokens last.
280
-
281
- > Why this matters: it's the difference between *learning context engineering by trying things* and *learning by burning your API budget*. The library treats $0 development as a first-class workflow, not an afterthought.
329
+ The same JSON shape that powered the audit trail and the cheap-model follow-up is the training payload. One recording, three downstream consumers, no extra instrumentation.
282
330
 
283
331
  ---
284
332
 
285
- ## Memory &mdash; one factory, four types, seven strategies
333
+ ## Mocks first, prod second
286
334
 
287
- `defineMemory({ type, strategy, store })` &mdash; one factory dispatches `type &times; strategy.kind` onto the right pipeline.
335
+ Generative AI development is expensive when every iteration hits a paid API. agentfootprint is designed so you build the entire app — agent, context engineering, memory, RAG — against in-memory mocks, prove the logic end-to-end with **zero API cost**, then swap real infrastructure in one boundary at a time.
288
336
 
289
- | Type | What's stored |
290
- |---|---|
291
- | `EPISODIC` | Raw conversation messages |
292
- | `SEMANTIC` | Extracted structured facts |
293
- | `NARRATIVE` | Beats / summaries of prior runs |
294
- | **`CAUSAL`** | **footprintjs decision-evidence snapshots** &mdash; replay "why" cross-run, zero hallucination |
295
-
296
- | Strategy | How content is selected |
297
- |---|---|
298
- | `WINDOW` | Last N entries (rule, no LLM, no embeddings) |
299
- | `BUDGET` | Fit-to-tokens (decider) |
300
- | `SUMMARIZE` | LLM compresses older turns |
301
- | `TOP_K` | Score-threshold semantic retrieval |
302
- | `EXTRACT` | LLM distills facts/beats on write |
303
- | `DECAY` | Recency-weighted (planned) |
304
- | `HYBRID` | Compose multiple |
305
-
306
- **Causal memory** is the differentiator: footprintjs's `decide()` and `select()` capture decision evidence as first-class events. Causal memory persists those snapshots tagged with the user's original query. New questions cosine-match past queries → inject the prior decision evidence → the LLM answers from EXACT past facts. Cross-run "why was X rejected last week?" follow-ups answer correctly without reconstruction.
337
+ | Boundary | Dev (mock) | Prod (swap one line) |
338
+ |---|---|---|
339
+ | LLM provider | `mock({ reply })` · `mock({ replies })` for scripted multi-turn | `anthropic()` · `openai()` · `bedrock()` · `ollama()` |
340
+ | Embedder | `mockEmbedder()` | OpenAI / Cohere / Bedrock embedder (factories on roadmap) |
341
+ | Memory store | `InMemoryStore` | `RedisStore` (`agentfootprint/memory-redis`) · `AgentCoreStore` (`agentfootprint/memory-agentcore`) · DynamoDB / Postgres / Pinecone (planned) |
342
+ | MCP server | `mockMcpClient({ tools })` — in-memory, no SDK | `mcpClient({ transport })` to a real server |
343
+ | Tool execution | inline closure | real implementation |
307
344
 
308
- The same snapshot data shape becomes RL/SFT/DPO training data in v2.1+.
345
+ The flowchart, recorders, narrative, and tests don't change between dev and prod. **Ship the patterns first; pay for tokens last.**
309
346
 
310
347
  ---
311
348
 
312
- ## Documentation
349
+ ## Pick your starting door
313
350
 
314
- | Resource | Link |
351
+ | If you are... | Start here |
315
352
  |---|---|
316
- | **Getting Started** | [Quick Start](https://footprintjs.github.io/agentfootprint/getting-started/quick-start/) &middot; [Key Concepts](https://footprintjs.github.io/agentfootprint/getting-started/key-concepts/) &middot; [Why agentfootprint?](https://footprintjs.github.io/agentfootprint/getting-started/why/) |
317
- | **Guides** | [Agent](https://footprintjs.github.io/agentfootprint/guides/agent/) &middot; [Memory](https://footprintjs.github.io/agentfootprint/guides/memory/) &middot; [Skills](https://footprintjs.github.io/agentfootprint/guides/skills-explained/) &middot; [Instructions](https://footprintjs.github.io/agentfootprint/guides/instructions/) &middot; [Streaming](https://footprintjs.github.io/agentfootprint/guides/streaming/) |
318
- | **Examples** | [33 runnable examples](https://github.com/footprintjs/agentfootprint/tree/main/examples) &mdash; primitives, compositions, patterns, context engineering, memory, runtime features |
319
- | **Integrations** | [Anthropic](https://footprintjs.github.io/agentfootprint/integrations/anthropic/) &middot; [OpenAI](https://footprintjs.github.io/agentfootprint/integrations/openai/) &middot; [AWS Bedrock](https://footprintjs.github.io/agentfootprint/integrations/aws-bedrock/) &middot; [Ollama](https://footprintjs.github.io/agentfootprint/integrations/ollama/) |
320
- | **Built on** | [footprintjs](https://github.com/footprintjs/footPrint) &mdash; the flowchart pattern for backend code |
353
+ | 🎓 **New to agents** | [5-minute Quick Start](https://footprintjs.github.io/agentfootprint/getting-started/quick-start/) first agent runs offline |
354
+ | 🛠️ **A LangChain / CrewAI / LangGraph user** | [Migration sketch](https://footprintjs.github.io/agentfootprint/getting-started/vs/) same patterns, fewer classes |
355
+ | 🏗️ **Architecting an enterprise rollout** | [Production guide](https://footprintjs.github.io/agentfootprint/guides/deployment/) multi-tenant identity, audit trails, redaction, OTel |
356
+ | 🔬 **Researcher / extending the framework** | [Extension guide](https://footprintjs.github.io/agentfootprint/contributing/extension-guide/) add a new flavor in 50 lines |
357
+
358
+ Every code snippet on the docs site is imported from a real, runnable file in [`examples/`](examples/) — every example is also an end-to-end test in CI. There is no docs-only code in this repo.
321
359
 
322
360
  ---
323
361
 
324
- ## What v2.0 ships (today)
362
+ ## What ships today
363
+
364
+ - **2 primitives** — `LLMCall`, `Agent` (the ReAct loop)
365
+ - **4 compositions** — `Sequence`, `Parallel`, `Conditional`, `Loop`
366
+ - **6 LLM providers** — Anthropic · OpenAI · Bedrock · Ollama · Browser-Anthropic · Browser-OpenAI · Mock (with `mock({ replies })` for scripted multi-turn)
367
+ - **One Injection primitive** — `defineSkill` / `defineSteering` / `defineInstruction` / `defineFact` (one engine, four typed factories, all reduce to `{ trigger, slot }`)
368
+ - **One Memory factory** — `defineMemory({ type, strategy, store })` — 4 types × 7 strategies including **Causal**
369
+ - **RAG** — `defineRAG()` + `indexDocuments()` (sugar over Semantic + TopK)
370
+ - **MCP** — `mcpClient({ transport })` for real servers · `mockMcpClient({ tools })` for in-memory development
371
+ - **Memory store adapters** — `InMemoryStore` · `RedisStore` (subpath `agentfootprint/memory-redis`) · `AgentCoreStore` (subpath `agentfootprint/memory-agentcore`)
372
+ - **47 typed observability events** across 13 domains — context · stream · agent · cost · skill · permission · eval · memory · …
373
+ - **Pause / resume** — JSON-serializable checkpoints; pause via `askHuman` / `pauseHere`, resume hours later on a different server
374
+ - **Resilience** — `withRetry`, `withFallback`, `resilientProvider`
375
+ - **AI-coding-tool support** — bundled instructions for Claude Code · Cursor · Windsurf · Cline · Kiro · Copilot
376
+ - **Runnable examples** organized by DNA layer (core · core-flow · patterns · context-engineering · memory · features) — every example is also an end-to-end CI test
377
+
378
+ ## What's next (clearly marked roadmap)
379
+
380
+ | Theme | Focus |
381
+ |---|---|
382
+ | **Reliability subsystem** | `CircuitBreaker` · 3-tier output fallback · auto-resume-on-error · Skills upgrades (`surfaceMode`, `refreshPolicy`) · `MockEnvironment` composer |
383
+ | **Causal training-data exports** | `causalMemory.exportForTraining({ format: 'sft' \| 'dpo' \| 'process' })` — production traffic becomes labeled SFT / DPO / process-RL trajectories |
384
+ | **Governance** | `Policy` · `BudgetTracker` · DynamoDB / Postgres / Pinecone memory adapters · production embedder factories |
385
+ | **Deep Agents · A2A protocol** | Planning-before-execution · agent-to-agent protocol · Lens UI deep-link |
325
386
 
326
- - **2 primitives** — `LLMCall`, `Agent` (ReAct loop)
327
- - **3 compositions + Loop** — Sequence · Parallel · Conditional · Loop
328
- - **6 LLM providers** — Anthropic · OpenAI · Bedrock · Ollama · Browser-Anthropic · Browser-OpenAI · Mock (for $0 testing)
329
- - **InjectionEngine** — one `Injection` primitive + 4 typed factories (`defineSkill` / `defineSteering` / `defineInstruction` / `defineFact`); covers Dynamic ReAct via `on-tool-return` triggers
330
- - **Memory subsystem** — `defineMemory` factory, 4 types (Episodic / Semantic / Narrative / **Causal** ⭐) × 7 strategies (Window / Budget / Summarize / TopK / Extract / Decay / Hybrid)
331
- - **Multi-agent through control flow** — no separate `MultiAgentSystem` class; agents compose via Sequence / Parallel / Conditional / Loop
332
- - **6 canonical patterns** runnable as examples — ReAct · Reflexion · ToT · Self-Consistency · Debate · Map-Reduce · Swarm
333
- - **Observability** — 47 typed events × 13 domains; recorders for context · stream · agent · cost · skill · permission · eval · memory
334
- - **Resilience helpers** — `withRetry`, `withFallback`, `resilientProvider`
335
- - **Pause / resume** — JSON-serializable checkpoints; agent can pause via `askHuman`/`pauseHere` and resume hours later on a different server
336
- - **AI-coding-tool support** — bundled instructions for Claude Code / Cursor / Windsurf / Cline / Kiro / Copilot
337
- - **33 runnable end-to-end examples** — every example is a real test exercising the documented surface
387
+ For shipped features per release see [CHANGELOG.md](./CHANGELOG.md). Roadmap items are *not* claims about the current API if a feature isn't in `npm install agentfootprint` today, it's listed here, not in the documentation.
338
388
 
339
- ## What's next
389
+ ---
340
390
 
341
- | Release | Focus |
342
- |---|---|
343
- | ~~v2.1~~ ✓ | RAG flavor (`defineRAG`) — shipped in 2.1.0 |
344
- | v2.2 | MCP integration (`mcpClient`) ✓ · Redis memory store adapter · CircuitBreaker primitive · 3-tier structured-output fallback |
345
- | v2.2 | Governance subsystem (`Policy`, `BudgetTracker`, role-based access) · DynamoDB / Postgres / Pinecone store adapters |
346
- | v2.3 | Causal training-data exports — `causalMemory.exportForTraining({ format: 'sft' \| 'dpo' \| 'process' })` for HuggingFace / OpenAI / Anthropic batch fine-tune |
347
- | v2.4+ | Deep Agents (planning-before-execution) · A2A protocol · Lens UI deep-link |
391
+ ## Built on
348
392
 
349
- ---
393
+ [footprintjs](https://github.com/footprintjs/footPrint) — the flowchart pattern for backend code. The decision-evidence capture, narrative recording, and time-travel checkpointing this library uses are footprintjs primitives. The same way autograd's forward-pass traversal is what makes gradient inspection automatic, footprintjs's flowchart traversal is what makes agentfootprint's typed-event stream and replayable traces automatic. You don't need to learn footprintjs to use agentfootprint — but if you want to build your own primitives at this depth, [start there](https://footprintjs.github.io/footPrint/).
394
+
395
+ ## License
350
396
 
351
- [MIT](./LICENSE) &copy; [Sanjay Krishna Anbalagan](https://github.com/sanjay1909)
397
+ [MIT](./LICENSE) © [Sanjay Krishna Anbalagan](https://github.com/sanjay1909)