agentfootprint 3.1.0 → 3.1.1
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/AGENTS.md +66 -47
- package/CLAUDE.md +47 -37
- package/README.md +27 -12
- package/dist/adapters/llm/createProvider.js +3 -2
- package/dist/adapters/llm/createProvider.js.map +1 -1
- package/dist/adapters/observability/agentcore.js +1 -0
- package/dist/adapters/observability/agentcore.js.map +1 -1
- package/dist/core/flowchartAsTool.js +5 -5
- package/dist/esm/adapters/llm/createProvider.js +3 -2
- package/dist/esm/adapters/llm/createProvider.js.map +1 -1
- package/dist/esm/adapters/observability/agentcore.js +1 -0
- package/dist/esm/adapters/observability/agentcore.js.map +1 -1
- package/dist/esm/core/flowchartAsTool.js +5 -5
- package/dist/esm/lib/lazyRequire.js +2 -30
- package/dist/esm/lib/lazyRequire.js.map +1 -1
- package/dist/esm/lib/rag/defineRAG.js +4 -2
- package/dist/esm/lib/rag/defineRAG.js.map +1 -1
- package/dist/esm/lib/rag/indexDocuments.js +2 -2
- package/dist/esm/locales/index.js +3 -3
- package/dist/esm/memory/beats/heuristicExtractor.js +1 -1
- package/dist/esm/memory/beats/heuristicExtractor.js.map +1 -1
- package/dist/esm/memory/beats/index.js +6 -6
- package/dist/esm/memory/beats/index.js.map +1 -1
- package/dist/esm/memory/beats/llmExtractor.js +1 -1
- package/dist/esm/memory/beats/llmExtractor.js.map +1 -1
- package/dist/esm/memory/embedding/index.js +4 -4
- package/dist/esm/memory/embedding/index.js.map +1 -1
- package/dist/esm/memory/entry/index.js +1 -1
- package/dist/esm/memory/entry/index.js.map +1 -1
- package/dist/esm/memory/facts/extractFacts.js +1 -1
- package/dist/esm/memory/facts/extractFacts.js.map +1 -1
- package/dist/esm/memory/facts/index.js +7 -7
- package/dist/esm/memory/facts/index.js.map +1 -1
- package/dist/esm/memory/facts/llmFactExtractor.js +1 -1
- package/dist/esm/memory/facts/llmFactExtractor.js.map +1 -1
- package/dist/esm/memory/facts/loadFacts.js +1 -1
- package/dist/esm/memory/facts/loadFacts.js.map +1 -1
- package/dist/esm/memory/facts/patternFactExtractor.js +1 -1
- package/dist/esm/memory/facts/patternFactExtractor.js.map +1 -1
- package/dist/esm/memory/identity/index.js +1 -1
- package/dist/esm/memory/identity/index.js.map +1 -1
- package/dist/esm/memory/pipeline/auto.js +2 -2
- package/dist/esm/memory/pipeline/auto.js.map +1 -1
- package/dist/esm/memory/pipeline/default.js +4 -4
- package/dist/esm/memory/pipeline/default.js.map +1 -1
- package/dist/esm/memory/pipeline/ephemeral.js +3 -3
- package/dist/esm/memory/pipeline/ephemeral.js.map +1 -1
- package/dist/esm/memory/pipeline/fact.js +5 -5
- package/dist/esm/memory/pipeline/fact.js.map +1 -1
- package/dist/esm/memory/pipeline/index.js +6 -6
- package/dist/esm/memory/pipeline/index.js.map +1 -1
- package/dist/esm/memory/pipeline/narrative.js +6 -6
- package/dist/esm/memory/pipeline/narrative.js.map +1 -1
- package/dist/esm/memory/pipeline/semantic.js +5 -5
- package/dist/esm/memory/pipeline/semantic.js.map +1 -1
- package/dist/esm/memory/stages/index.js +6 -6
- package/dist/esm/memory/stages/index.js.map +1 -1
- package/dist/esm/memory/stages/pickByBudget.js +1 -1
- package/dist/esm/memory/stages/pickByBudget.js.map +1 -1
- package/dist/esm/memory/store/InMemoryStore.js +2 -2
- package/dist/esm/memory/store/InMemoryStore.js.map +1 -1
- package/dist/esm/memory/store/index.js +1 -1
- package/dist/esm/memory/store/index.js.map +1 -1
- package/dist/esm/memory/wire/index.js +1 -1
- package/dist/esm/memory/wire/index.js.map +1 -1
- package/dist/esm/package.json +1 -0
- package/dist/esm/recorders/core/typedEmit.js +1 -1
- package/dist/esm/recorders/observability/BoundaryRecorder.js +3 -2
- package/dist/esm/recorders/observability/BoundaryRecorder.js.map +1 -1
- package/dist/esm/resilience/withRetry.js +3 -0
- package/dist/esm/resilience/withRetry.js.map +1 -1
- package/dist/esm/strategies/compose.js +2 -2
- package/dist/esm/tool-providers/skillScopedTools.js +3 -3
- package/dist/lib/lazyRequire.js +6 -0
- package/dist/lib/lazyRequire.js.map +1 -1
- package/dist/lib/rag/defineRAG.js +4 -2
- package/dist/lib/rag/defineRAG.js.map +1 -1
- package/dist/lib/rag/indexDocuments.js +2 -2
- package/dist/locales/index.js +3 -3
- package/dist/memory/beats/heuristicExtractor.js +4 -4
- package/dist/memory/beats/heuristicExtractor.js.map +1 -1
- package/dist/memory/beats/index.js +13 -13
- package/dist/memory/beats/index.js.map +1 -1
- package/dist/memory/beats/llmExtractor.js +2 -2
- package/dist/memory/beats/llmExtractor.js.map +1 -1
- package/dist/memory/embedding/index.js +8 -8
- package/dist/memory/embedding/index.js.map +1 -1
- package/dist/memory/entry/index.js +3 -3
- package/dist/memory/entry/index.js.map +1 -1
- package/dist/memory/facts/extractFacts.js +2 -2
- package/dist/memory/facts/extractFacts.js.map +1 -1
- package/dist/memory/facts/index.js +17 -17
- package/dist/memory/facts/index.js.map +1 -1
- package/dist/memory/facts/llmFactExtractor.js +2 -2
- package/dist/memory/facts/llmFactExtractor.js.map +1 -1
- package/dist/memory/facts/loadFacts.js +2 -2
- package/dist/memory/facts/loadFacts.js.map +1 -1
- package/dist/memory/facts/patternFactExtractor.js +2 -2
- package/dist/memory/facts/patternFactExtractor.js.map +1 -1
- package/dist/memory/identity/index.js +2 -2
- package/dist/memory/identity/index.js.map +1 -1
- package/dist/memory/pipeline/auto.js +11 -11
- package/dist/memory/pipeline/auto.js.map +1 -1
- package/dist/memory/pipeline/default.js +8 -8
- package/dist/memory/pipeline/default.js.map +1 -1
- package/dist/memory/pipeline/ephemeral.js +6 -6
- package/dist/memory/pipeline/ephemeral.js.map +1 -1
- package/dist/memory/pipeline/fact.js +11 -11
- package/dist/memory/pipeline/fact.js.map +1 -1
- package/dist/memory/pipeline/index.js +12 -12
- package/dist/memory/pipeline/index.js.map +1 -1
- package/dist/memory/pipeline/narrative.js +12 -12
- package/dist/memory/pipeline/narrative.js.map +1 -1
- package/dist/memory/pipeline/semantic.js +10 -10
- package/dist/memory/pipeline/semantic.js.map +1 -1
- package/dist/memory/stages/index.js +13 -13
- package/dist/memory/stages/index.js.map +1 -1
- package/dist/memory/stages/pickByBudget.js +3 -3
- package/dist/memory/stages/pickByBudget.js.map +1 -1
- package/dist/memory/store/InMemoryStore.js +5 -5
- package/dist/memory/store/InMemoryStore.js.map +1 -1
- package/dist/memory/store/index.js +2 -2
- package/dist/memory/store/index.js.map +1 -1
- package/dist/memory/wire/index.js +4 -4
- package/dist/memory/wire/index.js.map +1 -1
- package/dist/recorders/core/typedEmit.js +1 -1
- package/dist/recorders/observability/BoundaryRecorder.js +3 -2
- package/dist/recorders/observability/BoundaryRecorder.js.map +1 -1
- package/dist/resilience/withRetry.js +3 -0
- package/dist/resilience/withRetry.js.map +1 -1
- package/dist/strategies/compose.js +2 -2
- package/dist/tool-providers/skillScopedTools.js +3 -3
- package/dist/types/adapters/llm/createProvider.d.ts +3 -2
- package/dist/types/adapters/llm/createProvider.d.ts.map +1 -1
- package/dist/types/adapters/observability/agentcore.d.ts +1 -0
- package/dist/types/adapters/observability/agentcore.d.ts.map +1 -1
- package/dist/types/core/flowchartAsTool.d.ts +5 -5
- package/dist/types/lib/lazyRequire.d.ts.map +1 -1
- package/dist/types/lib/rag/defineRAG.d.ts +4 -2
- package/dist/types/lib/rag/defineRAG.d.ts.map +1 -1
- package/dist/types/lib/rag/indexDocuments.d.ts +2 -2
- package/dist/types/locales/index.d.ts +3 -3
- package/dist/types/memory/beats/extractBeats.d.ts +4 -4
- package/dist/types/memory/beats/extractBeats.d.ts.map +1 -1
- package/dist/types/memory/beats/extractor.d.ts +2 -2
- package/dist/types/memory/beats/extractor.d.ts.map +1 -1
- package/dist/types/memory/beats/formatAsNarrative.d.ts +1 -1
- package/dist/types/memory/beats/formatAsNarrative.d.ts.map +1 -1
- package/dist/types/memory/beats/heuristicExtractor.d.ts +1 -1
- package/dist/types/memory/beats/heuristicExtractor.d.ts.map +1 -1
- package/dist/types/memory/beats/index.d.ts +12 -12
- package/dist/types/memory/beats/index.d.ts.map +1 -1
- package/dist/types/memory/beats/llmExtractor.d.ts +2 -2
- package/dist/types/memory/beats/llmExtractor.d.ts.map +1 -1
- package/dist/types/memory/beats/writeBeats.d.ts +2 -2
- package/dist/types/memory/beats/writeBeats.d.ts.map +1 -1
- package/dist/types/memory/embedding/embedMessages.d.ts +3 -3
- package/dist/types/memory/embedding/embedMessages.d.ts.map +1 -1
- package/dist/types/memory/embedding/index.d.ts +8 -8
- package/dist/types/memory/embedding/index.d.ts.map +1 -1
- package/dist/types/memory/embedding/loadRelevant.d.ts +3 -3
- package/dist/types/memory/embedding/loadRelevant.d.ts.map +1 -1
- package/dist/types/memory/embedding/mockEmbedder.d.ts +1 -1
- package/dist/types/memory/embedding/mockEmbedder.d.ts.map +1 -1
- package/dist/types/memory/entry/decay.d.ts +1 -1
- package/dist/types/memory/entry/decay.d.ts.map +1 -1
- package/dist/types/memory/entry/index.d.ts +2 -2
- package/dist/types/memory/entry/index.d.ts.map +1 -1
- package/dist/types/memory/entry/types.d.ts +1 -1
- package/dist/types/memory/entry/types.d.ts.map +1 -1
- package/dist/types/memory/facts/extractFacts.d.ts +4 -4
- package/dist/types/memory/facts/extractFacts.d.ts.map +1 -1
- package/dist/types/memory/facts/extractor.d.ts +2 -2
- package/dist/types/memory/facts/extractor.d.ts.map +1 -1
- package/dist/types/memory/facts/formatFacts.d.ts +3 -3
- package/dist/types/memory/facts/formatFacts.d.ts.map +1 -1
- package/dist/types/memory/facts/index.d.ts +14 -14
- package/dist/types/memory/facts/index.d.ts.map +1 -1
- package/dist/types/memory/facts/llmFactExtractor.d.ts +2 -2
- package/dist/types/memory/facts/llmFactExtractor.d.ts.map +1 -1
- package/dist/types/memory/facts/loadFacts.d.ts +2 -2
- package/dist/types/memory/facts/loadFacts.d.ts.map +1 -1
- package/dist/types/memory/facts/patternFactExtractor.d.ts +1 -1
- package/dist/types/memory/facts/patternFactExtractor.d.ts.map +1 -1
- package/dist/types/memory/facts/writeFacts.d.ts +2 -2
- package/dist/types/memory/facts/writeFacts.d.ts.map +1 -1
- package/dist/types/memory/identity/index.d.ts +2 -2
- package/dist/types/memory/identity/index.d.ts.map +1 -1
- package/dist/types/memory/pipeline/auto.d.ts +6 -6
- package/dist/types/memory/pipeline/auto.d.ts.map +1 -1
- package/dist/types/memory/pipeline/default.d.ts +2 -2
- package/dist/types/memory/pipeline/default.d.ts.map +1 -1
- package/dist/types/memory/pipeline/ephemeral.d.ts +2 -2
- package/dist/types/memory/pipeline/ephemeral.d.ts.map +1 -1
- package/dist/types/memory/pipeline/fact.d.ts +3 -3
- package/dist/types/memory/pipeline/fact.d.ts.map +1 -1
- package/dist/types/memory/pipeline/index.d.ts +13 -13
- package/dist/types/memory/pipeline/index.d.ts.map +1 -1
- package/dist/types/memory/pipeline/narrative.d.ts +3 -3
- package/dist/types/memory/pipeline/narrative.d.ts.map +1 -1
- package/dist/types/memory/pipeline/semantic.d.ts +3 -3
- package/dist/types/memory/pipeline/semantic.d.ts.map +1 -1
- package/dist/types/memory/pipeline/types.d.ts +1 -1
- package/dist/types/memory/pipeline/types.d.ts.map +1 -1
- package/dist/types/memory/stages/formatDefault.d.ts +3 -3
- package/dist/types/memory/stages/formatDefault.d.ts.map +1 -1
- package/dist/types/memory/stages/index.d.ts +13 -13
- package/dist/types/memory/stages/index.d.ts.map +1 -1
- package/dist/types/memory/stages/loadRecent.d.ts +2 -2
- package/dist/types/memory/stages/loadRecent.d.ts.map +1 -1
- package/dist/types/memory/stages/pickByBudget.d.ts +2 -2
- package/dist/types/memory/stages/pickByBudget.d.ts.map +1 -1
- package/dist/types/memory/stages/summarize.d.ts +2 -2
- package/dist/types/memory/stages/summarize.d.ts.map +1 -1
- package/dist/types/memory/stages/tokenize.d.ts +1 -1
- package/dist/types/memory/stages/tokenize.d.ts.map +1 -1
- package/dist/types/memory/stages/types.d.ts +3 -3
- package/dist/types/memory/stages/types.d.ts.map +1 -1
- package/dist/types/memory/stages/writeMessages.d.ts +3 -3
- package/dist/types/memory/stages/writeMessages.d.ts.map +1 -1
- package/dist/types/memory/store/InMemoryStore.d.ts +3 -3
- package/dist/types/memory/store/InMemoryStore.d.ts.map +1 -1
- package/dist/types/memory/store/index.d.ts +2 -2
- package/dist/types/memory/store/index.d.ts.map +1 -1
- package/dist/types/memory/store/types.d.ts +2 -2
- package/dist/types/memory/store/types.d.ts.map +1 -1
- package/dist/types/memory/wire/index.d.ts +2 -2
- package/dist/types/memory/wire/index.d.ts.map +1 -1
- package/dist/types/memory/wire/mountMemoryPipeline.d.ts +1 -1
- package/dist/types/memory/wire/mountMemoryPipeline.d.ts.map +1 -1
- package/dist/types/recorders/core/typedEmit.d.ts +1 -1
- package/dist/types/recorders/observability/BoundaryRecorder.d.ts +3 -2
- package/dist/types/recorders/observability/BoundaryRecorder.d.ts.map +1 -1
- package/dist/types/recorders/observability/observeRunId.d.ts +1 -1
- package/dist/types/resilience/withRetry.d.ts +3 -0
- package/dist/types/resilience/withRetry.d.ts.map +1 -1
- package/dist/types/strategies/compose.d.ts +2 -2
- package/dist/types/tool-providers/skillScopedTools.d.ts +3 -3
- package/package.json +7 -3
package/AGENTS.md
CHANGED
|
@@ -44,7 +44,9 @@ const provider = mock({ reply: 'Refunds take 3 business days.' });
|
|
|
44
44
|
|
|
45
45
|
// Inline-mocked tool — no real backend yet.
|
|
46
46
|
const lookup = defineTool({
|
|
47
|
-
|
|
47
|
+
name: 'lookup',
|
|
48
|
+
description: '...',
|
|
49
|
+
inputSchema: { type: 'object', properties: {} },
|
|
48
50
|
execute: async () => 'mock data',
|
|
49
51
|
});
|
|
50
52
|
|
|
@@ -148,7 +150,8 @@ agent.rag(docs);
|
|
|
148
150
|
### Agent (ReAct primitive)
|
|
149
151
|
|
|
150
152
|
```typescript
|
|
151
|
-
import { Agent, defineTool
|
|
153
|
+
import { Agent, defineTool } from 'agentfootprint';
|
|
154
|
+
import { anthropic } from 'agentfootprint/llm-providers';
|
|
152
155
|
|
|
153
156
|
const agent = Agent.create({
|
|
154
157
|
provider: anthropic({ apiKey: process.env.ANTHROPIC_API_KEY! }),
|
|
@@ -172,7 +175,8 @@ Builder methods:
|
|
|
172
175
|
### LLMCall (one-shot primitive)
|
|
173
176
|
|
|
174
177
|
```typescript
|
|
175
|
-
import { LLMCall
|
|
178
|
+
import { LLMCall } from 'agentfootprint';
|
|
179
|
+
import { anthropic } from 'agentfootprint/llm-providers';
|
|
176
180
|
|
|
177
181
|
const call = LLMCall.create({ provider: anthropic(...), model: 'claude-sonnet-4-5-20250929' })
|
|
178
182
|
.system('You are a terse assistant.')
|
|
@@ -187,14 +191,12 @@ const answer = await call.run({ message: 'Summarize: ...' });
|
|
|
187
191
|
import { defineTool } from 'agentfootprint';
|
|
188
192
|
|
|
189
193
|
const weather = defineTool({
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
required: ['city'],
|
|
197
|
-
},
|
|
194
|
+
name: 'weather',
|
|
195
|
+
description: 'Current weather for a city.',
|
|
196
|
+
inputSchema: {
|
|
197
|
+
type: 'object',
|
|
198
|
+
properties: { city: { type: 'string' } },
|
|
199
|
+
required: ['city'],
|
|
198
200
|
},
|
|
199
201
|
execute: async (args) => `${(args as { city: string }).city}: 72°F`,
|
|
200
202
|
});
|
|
@@ -330,33 +332,34 @@ There is **no** `MultiAgentSystem` class. Multi-agent = compositions of single A
|
|
|
330
332
|
```typescript
|
|
331
333
|
import { Sequence, Parallel, Conditional, Loop } from 'agentfootprint';
|
|
332
334
|
|
|
333
|
-
// Output flows downstream
|
|
335
|
+
// Output flows downstream — every step needs an id + a runner
|
|
334
336
|
const pipeline = Sequence.create()
|
|
335
|
-
.step(researcher)
|
|
336
|
-
.step(writer)
|
|
337
|
-
.step(editor)
|
|
337
|
+
.step('research', researcher) // each runner is an Agent / LLMCall / composition
|
|
338
|
+
.step('write', writer)
|
|
339
|
+
.step('edit', editor)
|
|
338
340
|
.build();
|
|
339
341
|
|
|
340
|
-
// Multi-perspective with merge
|
|
342
|
+
// Multi-perspective with LLM merge — branches need ids; rank via mergeWithLLM
|
|
341
343
|
const tot = Parallel.create()
|
|
342
|
-
.branch(thoughtAgent)
|
|
343
|
-
.branch(thoughtAgent)
|
|
344
|
-
.branch(thoughtAgent)
|
|
345
|
-
.
|
|
344
|
+
.branch('a', thoughtAgent)
|
|
345
|
+
.branch('b', thoughtAgent)
|
|
346
|
+
.branch('c', thoughtAgent)
|
|
347
|
+
.mergeWithLLM({ provider, model: 'mock', prompt: 'Pick the best answer.' })
|
|
346
348
|
.build();
|
|
349
|
+
// (or .mergeWithFn((results) => ...) to merge in code)
|
|
347
350
|
|
|
348
|
-
// Predicate-based routing
|
|
351
|
+
// Predicate-based routing — .when(id, predicate, runner); .otherwise is mandatory
|
|
349
352
|
const triage = Conditional.create()
|
|
350
|
-
.when((
|
|
351
|
-
.when((
|
|
352
|
-
.otherwise(generalAgent)
|
|
353
|
+
.when('billing', (input) => /refund|invoice/i.test(input.message), billingAgent)
|
|
354
|
+
.when('tech', (input) => /error|bug/i.test(input.message), techAgent)
|
|
355
|
+
.otherwise('general', generalAgent)
|
|
353
356
|
.build();
|
|
354
357
|
|
|
355
|
-
// Iterate with budget
|
|
358
|
+
// Iterate with a REQUIRED budget — .repeat(body) + .times(n) / .forAtMost(ms) / .until(guard)
|
|
356
359
|
const refine = Loop.create()
|
|
357
|
-
.
|
|
358
|
-
.
|
|
359
|
-
.
|
|
360
|
+
.repeat(critiqueAgent)
|
|
361
|
+
.until(({ iteration, latestOutput }) => latestOutput.includes('DONE'))
|
|
362
|
+
.times(5)
|
|
360
363
|
.build();
|
|
361
364
|
```
|
|
362
365
|
|
|
@@ -377,7 +380,9 @@ Browse [`examples/patterns/`](examples/patterns/) — every pattern is a runnabl
|
|
|
377
380
|
### Providers
|
|
378
381
|
|
|
379
382
|
```typescript
|
|
380
|
-
import {
|
|
383
|
+
import { mock } from 'agentfootprint';
|
|
384
|
+
// Vendor-SDK providers (lazy peer-deps) live on the dedicated subpath:
|
|
385
|
+
import { anthropic, openai, bedrock, ollama } from 'agentfootprint/llm-providers';
|
|
381
386
|
|
|
382
387
|
// Adapter-swap testing: same agent, different provider, $0 in CI
|
|
383
388
|
const provider = process.env.NODE_ENV === 'production'
|
|
@@ -385,7 +390,12 @@ const provider = process.env.NODE_ENV === 'production'
|
|
|
385
390
|
: mock({ reply: 'test response' });
|
|
386
391
|
```
|
|
387
392
|
|
|
388
|
-
Every provider implements the same `LLMProvider` interface.
|
|
393
|
+
Every provider implements the same `LLMProvider` interface. `mock`,
|
|
394
|
+
`browserAnthropic`, `browserOpenai`, and `createProvider` ship on the main
|
|
395
|
+
barrel; the vendor-SDK-backed providers (`anthropic` · `openai` · `bedrock`
|
|
396
|
+
· `ollama`) live ONLY at `agentfootprint/llm-providers` (legacy alias:
|
|
397
|
+
`agentfootprint/providers`) so bundlers never walk their lazy peer-dep
|
|
398
|
+
requires. Browser variants exist for client-side use.
|
|
389
399
|
|
|
390
400
|
### Pause / Resume (Human-in-the-Loop)
|
|
391
401
|
|
|
@@ -393,8 +403,13 @@ Every provider implements the same `LLMProvider` interface. Browser variants exi
|
|
|
393
403
|
import { askHuman, pauseHere, isPaused } from 'agentfootprint';
|
|
394
404
|
|
|
395
405
|
const approveTool = defineTool({
|
|
396
|
-
|
|
397
|
-
|
|
406
|
+
name: 'approve',
|
|
407
|
+
description: 'Ask a human.',
|
|
408
|
+
inputSchema: { type: 'object', properties: { amount: { type: 'number' } } },
|
|
409
|
+
// askHuman() / pauseHere() throw a PauseRequest — CALL them inside
|
|
410
|
+
// execute, don't pass them as the execute function.
|
|
411
|
+
execute: async (args) =>
|
|
412
|
+
askHuman({ question: `Approve $${(args as { amount: number }).amount}?` }),
|
|
398
413
|
});
|
|
399
414
|
|
|
400
415
|
const result = await agent.run({ message: 'Refund $500?' });
|
|
@@ -408,14 +423,20 @@ if (isPaused(result)) {
|
|
|
408
423
|
### Resilience
|
|
409
424
|
|
|
410
425
|
```typescript
|
|
411
|
-
import { withRetry, withFallback,
|
|
426
|
+
import { withRetry, withFallback, fallbackProvider, withCircuitBreaker } from 'agentfootprint/resilience';
|
|
427
|
+
import { anthropic, openai, ollama } from 'agentfootprint/llm-providers';
|
|
412
428
|
|
|
413
|
-
const reliable = withRetry(provider, {
|
|
429
|
+
const reliable = withRetry(provider, { maxAttempts: 3 });
|
|
414
430
|
const resilient = withFallback(primary, fallback);
|
|
415
|
-
const chain =
|
|
431
|
+
const chain = fallbackProvider(anthropic({...}), openai({...}), ollama({...}));
|
|
432
|
+
const guarded = withCircuitBreaker(provider);
|
|
416
433
|
```
|
|
417
434
|
|
|
418
|
-
|
|
435
|
+
Resilience decorators live on the `agentfootprint/resilience` subpath
|
|
436
|
+
(not the main barrel). Each preserves the `LLMProvider` interface and
|
|
437
|
+
stacks freely.
|
|
438
|
+
|
|
439
|
+
### Observability — 59 typed events across 16 domains
|
|
419
440
|
|
|
420
441
|
```typescript
|
|
421
442
|
agent.on('agentfootprint.context.injected', (e) =>
|
|
@@ -440,7 +461,7 @@ Recorders (auto-attached when relevant builder method is called):
|
|
|
440
461
|
|
|
441
462
|
- ❌ **Don't ship a `ReflexionAgent` class.** Compose `Sequence(Agent, critique-LLM, Agent)`.
|
|
442
463
|
- ❌ **Don't use `agent.run('string')`** — use `agent.run({ message: '...', identity? })`.
|
|
443
|
-
- ❌ **Don't import from
|
|
464
|
+
- ❌ **Don't import from non-existent subpaths** like `'agentfootprint/instructions'` — the injection factories live on the main barrel (or `'agentfootprint/injection-engine'`). NOTE: `'agentfootprint/observe'`, `'agentfootprint/security'`, `'agentfootprint/resilience'`, `'agentfootprint/llm-providers'`, `'agentfootprint/memory'`, `'agentfootprint/tool-providers'`, `'agentfootprint/locales'` ARE real subpaths — some surfaces (vendor providers, resilience decorators) live ONLY there, not on the main barrel.
|
|
444
465
|
- ❌ **Don't use `.memoryPipeline(pipeline)`** — that's the v1 API. Use `.memory(defineMemory({...}))`.
|
|
445
466
|
- ❌ **Don't fall back when TopK threshold returns nothing.** Strict semantics: garbage past context > none is wrong.
|
|
446
467
|
- ❌ **Don't store closures or class instances in scope** — TransactionBuffer can't clone functions. Memory-store entries serialize to JSON.
|
|
@@ -471,10 +492,10 @@ Recorders (auto-attached when relevant builder method is called):
|
|
|
471
492
|
## Build & Test
|
|
472
493
|
|
|
473
494
|
```bash
|
|
474
|
-
npm install agentfootprint footprintjs
|
|
475
|
-
npm test # vitest run
|
|
495
|
+
npm install agentfootprint footprintjs # footprintjs ^6 is a peer dependency
|
|
496
|
+
npm test # vitest run
|
|
476
497
|
npm run example examples/... # run a single example end-to-end
|
|
477
|
-
npm run examples
|
|
498
|
+
npm run test:examples # typecheck + run every example
|
|
478
499
|
```
|
|
479
500
|
|
|
480
501
|
## Package layout
|
|
@@ -489,10 +510,10 @@ src/
|
|
|
489
510
|
├── memory/ — defineMemory + 4 types × 7 strategies + InMemoryStore + Causal
|
|
490
511
|
├── adapters/llm/ — Anthropic, OpenAI, Bedrock, Ollama, Browser variants, Mock
|
|
491
512
|
├── recorders/ — context, stream, agent, cost, skill, permission, eval, memory
|
|
492
|
-
├── resilience/ — withRetry, withFallback,
|
|
513
|
+
├── resilience/ — withRetry, withFallback, fallbackProvider, withCircuitBreaker
|
|
493
514
|
└── stream.ts — SSE formatter
|
|
494
515
|
|
|
495
|
-
examples/ —
|
|
516
|
+
examples/ — runnable end-to-end tests organized by DNA layer
|
|
496
517
|
├── core/ — primitives
|
|
497
518
|
├── core-flow/ — compositions
|
|
498
519
|
├── patterns/ — canonical recipes
|
|
@@ -503,10 +524,8 @@ examples/ — 33 runnable end-to-end tests organized by DNA layer
|
|
|
503
524
|
|
|
504
525
|
## Roadmap (informs what to defer)
|
|
505
526
|
|
|
506
|
-
- **
|
|
507
|
-
- **v2.
|
|
508
|
-
- **
|
|
509
|
-
- **v2.3** — Causal training-data exports (SFT / DPO / process-RL)
|
|
510
|
-
- **v2.4+** — Deep Agents · A2A protocol · Lens UI integration
|
|
527
|
+
- **v3.1 (current)** — primitives + compositions + InjectionEngine + Memory (incl. Causal) + providers + RAG (`defineRAG`) + MCP (`mcpClient`) + Redis/AgentCore memory adapters + resilience (retry / fallback / circuit breaker) + Permission policy + observability subsystem
|
|
528
|
+
- **Shipped since v2.0** — RAG flavor · Redis memory adapter · MCP integration · CircuitBreaker · governance (PermissionPolicy)
|
|
529
|
+
- **Planned** — Causal training-data exports (SFT / DPO / process-RL) · DynamoDB / Postgres / Pinecone adapters · Deep Agents · A2A protocol · Lens UI integration
|
|
511
530
|
|
|
512
531
|
When in doubt — read [`examples/`](examples/), every file is a runnable spec.
|
package/CLAUDE.md
CHANGED
|
@@ -54,7 +54,7 @@ await agent.run({ message: 'How long does a refund take?' });
|
|
|
54
54
|
|
|
55
55
|
| Boundary | Mock for development | Production swap |
|
|
56
56
|
|---|---|---|
|
|
57
|
-
| LLM provider | `mock({ reply })` · `mock({ replies })` for scripted ReAct | `anthropic()` · `openai()` · `bedrock()` · `ollama()` |
|
|
57
|
+
| LLM provider | `mock({ reply })` · `mock({ replies })` for scripted ReAct | `anthropic()` · `openai()` · `bedrock()` · `ollama()` (from `agentfootprint/llm-providers`) |
|
|
58
58
|
| Embedder | `mockEmbedder()` | OpenAI / Cohere / Bedrock embedder factory |
|
|
59
59
|
| Memory store | `InMemoryStore` | `RedisStore` (`agentfootprint/memory-redis`) · `AgentCoreStore` (`agentfootprint/memory-agentcore`) · DynamoDB / Postgres / Pinecone (planned) |
|
|
60
60
|
| MCP server | `mockMcpClient({ tools })` — in-memory, no SDK | `mcpClient({ transport })` to a real server |
|
|
@@ -148,7 +148,8 @@ agent.rag(docs);
|
|
|
148
148
|
### Agent (ReAct primitive)
|
|
149
149
|
|
|
150
150
|
```typescript
|
|
151
|
-
import { Agent, defineTool
|
|
151
|
+
import { Agent, defineTool } from 'agentfootprint';
|
|
152
|
+
import { anthropic } from 'agentfootprint/llm-providers';
|
|
152
153
|
|
|
153
154
|
const agent = Agent.create({
|
|
154
155
|
provider: anthropic({ apiKey: process.env.ANTHROPIC_API_KEY! }),
|
|
@@ -172,7 +173,8 @@ Builder methods:
|
|
|
172
173
|
### LLMCall (one-shot primitive)
|
|
173
174
|
|
|
174
175
|
```typescript
|
|
175
|
-
import { LLMCall
|
|
176
|
+
import { LLMCall } from 'agentfootprint';
|
|
177
|
+
import { anthropic } from 'agentfootprint/llm-providers';
|
|
176
178
|
|
|
177
179
|
const call = LLMCall.create({ provider: anthropic(...), model: 'claude-sonnet-4-5-20250929' })
|
|
178
180
|
.system('You are a terse assistant.')
|
|
@@ -330,33 +332,35 @@ There is **no** `MultiAgentSystem` class. Multi-agent = compositions of single A
|
|
|
330
332
|
```typescript
|
|
331
333
|
import { Sequence, Parallel, Conditional, Loop } from 'agentfootprint';
|
|
332
334
|
|
|
333
|
-
// Output flows downstream
|
|
335
|
+
// Output flows downstream — each step takes an id + a runner (Agent / LLMCall / runner)
|
|
334
336
|
const pipeline = Sequence.create()
|
|
335
|
-
.step(researcher)
|
|
336
|
-
.step(writer)
|
|
337
|
-
.step(editor)
|
|
337
|
+
.step('research', researcher)
|
|
338
|
+
.step('write', writer)
|
|
339
|
+
.step('edit', editor)
|
|
338
340
|
.build();
|
|
339
341
|
|
|
340
|
-
// Multi-perspective with merge
|
|
342
|
+
// Multi-perspective with LLM merge — each branch takes an id + a runner
|
|
341
343
|
const tot = Parallel.create()
|
|
342
|
-
.branch(thoughtAgent)
|
|
343
|
-
.branch(thoughtAgent)
|
|
344
|
-
.branch(thoughtAgent)
|
|
345
|
-
.
|
|
344
|
+
.branch('t1', thoughtAgent)
|
|
345
|
+
.branch('t2', thoughtAgent)
|
|
346
|
+
.branch('t3', thoughtAgent)
|
|
347
|
+
.mergeWithLLM({ provider, model: 'claude-sonnet-4-5-20250929', prompt: 'Rank and synthesize.' })
|
|
346
348
|
.build();
|
|
347
349
|
|
|
348
|
-
// Predicate-based routing
|
|
350
|
+
// Predicate-based routing — .when(id, predicate, runner); exactly one .otherwise(id, runner).
|
|
351
|
+
// predicate receives ConditionalInput { message }.
|
|
349
352
|
const triage = Conditional.create()
|
|
350
|
-
.when((
|
|
351
|
-
.when((
|
|
352
|
-
.otherwise(generalAgent)
|
|
353
|
+
.when('billing', (input) => /refund|invoice/i.test(input.message), billingAgent)
|
|
354
|
+
.when('tech', (input) => /error|bug/i.test(input.message), techAgent)
|
|
355
|
+
.otherwise('general', generalAgent)
|
|
353
356
|
.build();
|
|
354
357
|
|
|
355
|
-
// Iterate with budget
|
|
358
|
+
// Iterate with budget — .repeat(runner) sets the body, .times(n) caps iterations.
|
|
359
|
+
// until() guard receives { iteration, latestOutput, startMs }.
|
|
356
360
|
const refine = Loop.create()
|
|
357
|
-
.
|
|
358
|
-
.
|
|
359
|
-
.
|
|
361
|
+
.repeat(critiqueAgent)
|
|
362
|
+
.until((ctx) => /done/i.test(ctx.latestOutput))
|
|
363
|
+
.times(5)
|
|
360
364
|
.build();
|
|
361
365
|
```
|
|
362
366
|
|
|
@@ -377,7 +381,8 @@ Browse [`examples/patterns/`](examples/patterns/) — every pattern is a runnabl
|
|
|
377
381
|
### Providers
|
|
378
382
|
|
|
379
383
|
```typescript
|
|
380
|
-
import {
|
|
384
|
+
import { mock } from 'agentfootprint'; // zero-peer-dep, on the main barrel
|
|
385
|
+
import { anthropic, openai, bedrock, ollama } from 'agentfootprint/llm-providers'; // vendor-SDK-backed
|
|
381
386
|
|
|
382
387
|
// Adapter-swap testing: same agent, different provider, $0 in CI
|
|
383
388
|
const provider = process.env.NODE_ENV === 'production'
|
|
@@ -385,7 +390,7 @@ const provider = process.env.NODE_ENV === 'production'
|
|
|
385
390
|
: mock({ reply: 'test response' });
|
|
386
391
|
```
|
|
387
392
|
|
|
388
|
-
Every provider implements the same `LLMProvider` interface.
|
|
393
|
+
Every provider implements the same `LLMProvider` interface. The vendor-SDK providers (`anthropic`, `openai`, `bedrock`, `ollama`, plus their `*Provider` classes) live ONLY at `agentfootprint/llm-providers` (legacy alias `agentfootprint/providers`) — kept off the main barrel so bundlers never walk the lazy peer-dep requires. The main barrel exports the zero-peer-dep providers: `mock`, `browserAnthropic`, `browserOpenai`, and `createProvider`.
|
|
389
394
|
|
|
390
395
|
### Pause / Resume (Human-in-the-Loop)
|
|
391
396
|
|
|
@@ -394,7 +399,12 @@ import { askHuman, pauseHere, isPaused } from 'agentfootprint';
|
|
|
394
399
|
|
|
395
400
|
const approveTool = defineTool({
|
|
396
401
|
schema: { name: 'approve', description: 'Ask a human.', inputSchema: { ... } },
|
|
397
|
-
|
|
402
|
+
// askHuman()/pauseHere() THROW a PauseRequest — call them INSIDE execute,
|
|
403
|
+
// do not assign them as the execute function.
|
|
404
|
+
execute: async (args) => {
|
|
405
|
+
askHuman({ question: `Approve this action?`, risk: 'high' });
|
|
406
|
+
return ''; // unreachable — askHuman always throws
|
|
407
|
+
},
|
|
398
408
|
});
|
|
399
409
|
|
|
400
410
|
const result = await agent.run({ message: 'Refund $500?' });
|
|
@@ -408,14 +418,17 @@ if (isPaused(result)) {
|
|
|
408
418
|
### Resilience
|
|
409
419
|
|
|
410
420
|
```typescript
|
|
411
|
-
import { withRetry, withFallback,
|
|
421
|
+
import { withRetry, withFallback, fallbackProvider } from 'agentfootprint/resilience';
|
|
422
|
+
import { anthropic, openai, ollama } from 'agentfootprint/llm-providers';
|
|
412
423
|
|
|
413
|
-
const reliable = withRetry(provider, {
|
|
424
|
+
const reliable = withRetry(provider, { maxAttempts: 3 });
|
|
414
425
|
const resilient = withFallback(primary, fallback);
|
|
415
|
-
const chain =
|
|
426
|
+
const chain = fallbackProvider(anthropic({...}), openai({...}), ollama({...}));
|
|
416
427
|
```
|
|
417
428
|
|
|
418
|
-
|
|
429
|
+
Also available: `withCircuitBreaker(provider, opts?)`. The resilience decorators live ONLY at `agentfootprint/resilience` (not the main barrel).
|
|
430
|
+
|
|
431
|
+
### Observability — 59 typed events × 16 domains
|
|
419
432
|
|
|
420
433
|
```typescript
|
|
421
434
|
agent.on('agentfootprint.context.injected', (e) =>
|
|
@@ -440,7 +453,7 @@ Recorders (auto-attached when relevant builder method is called):
|
|
|
440
453
|
|
|
441
454
|
- ❌ **Don't ship a `ReflexionAgent` class.** Compose `Sequence(Agent, critique-LLM, Agent)`.
|
|
442
455
|
- ❌ **Don't use `agent.run('string')`** — use `agent.run({ message: '...', identity? })`.
|
|
443
|
-
- ❌ **Don't import from
|
|
456
|
+
- ❌ **Don't import from removed subpaths** like `'agentfootprint/instructions'` — the injection factories are on the main barrel (or `'agentfootprint/injection-engine'`). NOTE: `'agentfootprint/observe'`, `'agentfootprint/security'`, `'agentfootprint/resilience'`, `'agentfootprint/llm-providers'` ARE real, current subpaths — some symbols (e.g. `buildStepGraph`, `extractSequence`, the resilience decorators, the vendor-SDK providers) are intentionally subpath-only, NOT on the main barrel.
|
|
444
457
|
- ❌ **Don't use `.memoryPipeline(pipeline)`** — that's the v1 API. Use `.memory(defineMemory({...}))`.
|
|
445
458
|
- ❌ **Don't fall back when TopK threshold returns nothing.** Strict semantics: garbage past context > none is wrong.
|
|
446
459
|
- ❌ **Don't store closures or class instances in scope** — TransactionBuffer can't clone functions. Memory-store entries serialize to JSON.
|
|
@@ -472,9 +485,9 @@ Recorders (auto-attached when relevant builder method is called):
|
|
|
472
485
|
|
|
473
486
|
```bash
|
|
474
487
|
npm install agentfootprint footprintjs
|
|
475
|
-
npm test # vitest run —
|
|
488
|
+
npm test # vitest run — 2000+ tests
|
|
476
489
|
npm run example examples/... # run a single example end-to-end
|
|
477
|
-
npm run examples
|
|
490
|
+
npm run test:examples # typecheck + run every example end-to-end
|
|
478
491
|
```
|
|
479
492
|
|
|
480
493
|
## Package layout
|
|
@@ -489,10 +502,10 @@ src/
|
|
|
489
502
|
├── memory/ — defineMemory + 4 types × 7 strategies + InMemoryStore + Causal
|
|
490
503
|
├── adapters/llm/ — Anthropic, OpenAI, Bedrock, Ollama, Browser variants, Mock
|
|
491
504
|
├── recorders/ — context, stream, agent, cost, skill, permission, eval, memory
|
|
492
|
-
├── resilience/ — withRetry, withFallback,
|
|
505
|
+
├── resilience/ — withRetry, withFallback, fallbackProvider, withCircuitBreaker
|
|
493
506
|
└── stream.ts — SSE formatter
|
|
494
507
|
|
|
495
|
-
examples/ —
|
|
508
|
+
examples/ — 47 runnable end-to-end tests organized by DNA layer
|
|
496
509
|
├── core/ — primitives
|
|
497
510
|
├── core-flow/ — compositions
|
|
498
511
|
├── patterns/ — canonical recipes
|
|
@@ -503,10 +516,7 @@ examples/ — 33 runnable end-to-end tests organized by DNA layer
|
|
|
503
516
|
|
|
504
517
|
## Roadmap (informs what to defer)
|
|
505
518
|
|
|
506
|
-
- **
|
|
507
|
-
- **
|
|
508
|
-
- **v2.2** — Governance (Policy + BudgetTracker) · DynamoDB / Postgres / Pinecone adapters
|
|
509
|
-
- **v2.3** — Causal training-data exports (SFT / DPO / process-RL)
|
|
510
|
-
- **v2.4+** — Deep Agents · A2A protocol · Lens UI integration
|
|
519
|
+
- **Shipped (v3.x current)** — primitives + compositions + InjectionEngine + Memory (incl. Causal) + providers (vendor-SDK + browser + mock) + RAG (`defineRAG`) + MCP (`mcpClient`) + Redis/AgentCore memory adapters + resilience (`withRetry` / `withFallback` / `fallbackProvider` / `withCircuitBreaker`) + reliability subsystem + governance (`PermissionPolicy`) + observability subpaths (`/observe`, `/thinking`, `/locales`, `/status`)
|
|
520
|
+
- **Planned** — BudgetTracker · DynamoDB / Postgres / Pinecone memory adapters · Causal training-data exports (SFT / DPO / process-RL) · Deep Agents · A2A protocol · Lens UI integration
|
|
511
521
|
|
|
512
522
|
When in doubt — read [`examples/`](examples/), every file is a runnable spec.
|
package/README.md
CHANGED
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
<a href="https://github.com/footprintjs/agentfootprint/actions"><img src="https://github.com/footprintjs/agentfootprint/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
19
19
|
<!-- coverage-badge --><img src="https://img.shields.io/badge/coverage-87%25-green.svg" alt="coverage: 87%"><!-- /coverage-badge -->
|
|
20
20
|
<a href="https://www.npmjs.com/package/agentfootprint"><img src="https://img.shields.io/npm/v/agentfootprint.svg?style=flat" alt="npm version"></a>
|
|
21
|
+
<a href="https://bundlephobia.com/package/agentfootprint"><img src="https://img.shields.io/bundlephobia/minzip/agentfootprint?label=minzipped" alt="minzipped size"></a>
|
|
22
|
+
<a href="#tree-shakeable--esm-first"><img src="https://img.shields.io/badge/tree--shakeable-%E2%9C%93-success?style=flat" alt="tree-shakeable"></a>
|
|
21
23
|
<a href="https://www.npmjs.com/package/agentfootprint"><img src="https://img.shields.io/npm/dm/agentfootprint.svg" alt="Downloads"></a>
|
|
22
24
|
<a href="https://github.com/footprintjs/agentfootprint/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT"></a>
|
|
23
25
|
</p>
|
|
@@ -54,15 +56,15 @@ That's the whole model: `Injection = slot × trigger × cache`.
|
|
|
54
56
|
|
|
55
57
|
### The 4 triggers
|
|
56
58
|
|
|
57
|
-
| Trigger | Flavor | Fires when |
|
|
59
|
+
| Trigger | Flavor | Fires when | Illustration | Default slot |
|
|
58
60
|
|---|---|---|---|---|
|
|
59
|
-
| `always` | static | Every iteration | `.steering('You are a triage agent…')` | `system` |
|
|
60
|
-
| `rule` | runtime — predicate | Your rule returns true | `.
|
|
61
|
-
| `on-tool-return` | runtime — lifecycle | After a specific tool returns | `.instruction({
|
|
62
|
-
| `llm-activated` | runtime — agent-driven | LLM calls `read_skill('id')` | `.skill({ id: 'refund-policy',
|
|
61
|
+
| `always` | static | Every iteration | `.steering(defineSteering({ id, prompt: 'You are a triage agent…' }))` | `system` |
|
|
62
|
+
| `rule` | runtime — predicate | Your rule returns true | `.instruction(defineInstruction({ id, activeWhen: s => /price\|refund/.test(s.userQuery), prompt }))` | `system` |
|
|
63
|
+
| `on-tool-return` | runtime — lifecycle | After a specific tool returns | `.instruction(defineInstruction({ id, slot: 'messages', activeWhen, prompt: 'Cite source IDs.' }))` | `messages` |
|
|
64
|
+
| `llm-activated` | runtime — agent-driven | LLM calls `read_skill('id')` | `.skill(defineSkill({ id: 'refund-policy', description, body, viaToolName: 'read_skill' }))` | `messages` (body) |
|
|
63
65
|
|
|
64
66
|
> [!NOTE]
|
|
65
|
-
> Slot is a default, not a coupling — the same `Skill` can live in `tools` (schema only, discovered via `read_skill`), `messages` (body injected on activation), or `system` (baked into the prompt as steering).
|
|
67
|
+
> The "Illustration" column shows the shape of each flavor — the typed builder methods (`.steering` / `.instruction` / `.skill` / `.fact` / `.rag`) take an `Injection` (or `MemoryDefinition` for `.rag`) produced by the matching `defineSteering` / `defineInstruction` / `defineSkill` / `defineFact` / `defineRAG` factory. Slot is a default, not a coupling — the same `Skill` can live in `tools` (schema only, discovered via `read_skill`), `messages` (body injected on activation), or `system` (baked into the prompt as steering).
|
|
66
68
|
|
|
67
69
|
**3 slots × 4 triggers × N flavors = the entire context-engineering surface.**
|
|
68
70
|
|
|
@@ -204,8 +206,8 @@ const fan = Parallel.create()
|
|
|
204
206
|
import { Conditional } from 'agentfootprint';
|
|
205
207
|
|
|
206
208
|
const router = Conditional.create()
|
|
207
|
-
.when('billing', s => s.
|
|
208
|
-
.when('tech', s => s.
|
|
209
|
+
.when('billing', s => /bill|invoice|refund/.test(s.message), billingAgent)
|
|
210
|
+
.when('tech', s => /error|bug|crash/.test(s.message), techAgent)
|
|
209
211
|
.otherwise('default', defaultAgent)
|
|
210
212
|
.build();
|
|
211
213
|
```
|
|
@@ -227,7 +229,7 @@ import { Loop } from 'agentfootprint';
|
|
|
227
229
|
|
|
228
230
|
const reflexion = Loop.create()
|
|
229
231
|
.repeat(thinkAgent)
|
|
230
|
-
.until(
|
|
232
|
+
.until(({ latestOutput }) => latestOutput.includes('DONE'))
|
|
231
233
|
.build();
|
|
232
234
|
```
|
|
233
235
|
|
|
@@ -270,7 +272,8 @@ Pick the flows that match your problem. Chain them. **That's your Agentic Applic
|
|
|
270
272
|
```typescript
|
|
271
273
|
const research = Loop.create()
|
|
272
274
|
.repeat(Sequence.create().step('plan', plan).step('search', searchAll).build())
|
|
273
|
-
.until(
|
|
275
|
+
.until(({ iteration, latestOutput }) => iteration >= 3 || latestOutput.includes('DONE'))
|
|
276
|
+
.build();
|
|
274
277
|
```
|
|
275
278
|
|
|
276
279
|
Same `.create().method().build()` shape as the four rows above — just composed.
|
|
@@ -367,7 +370,7 @@ const result = await agent.run({ message: 'Weather in Paris?' });
|
|
|
367
370
|
console.log(result); // → "I checked: it is 72°F and sunny."
|
|
368
371
|
```
|
|
369
372
|
|
|
370
|
-
|
|
373
|
+
For production, import a real provider from `agentfootprint/llm-providers` and swap it in — `anthropic(...)` / `openai(...)` / `bedrock(...)` / `ollama(...)`. Only the import line changes; the agent code stays the same. (The vendor-SDK providers live on the `agentfootprint/llm-providers` subpath so the main `agentfootprint` barrel stays free of optional peer-dep requires; `mock`, `browserAnthropic`, and `browserOpenai` are on the main barrel.)
|
|
371
374
|
|
|
372
375
|
---
|
|
373
376
|
|
|
@@ -393,7 +396,7 @@ The flowchart, recorders, and tests don't change between dev and prod.
|
|
|
393
396
|
- 4 control flows — `Sequence`, `Parallel`, `Conditional`, `Loop`
|
|
394
397
|
- 1 Injection primitive — `defineSkill` / `defineSteering` / `defineInstruction` / `defineFact`
|
|
395
398
|
- 1 reliability gate — `.reliability({ preCheck, postDecide, providers, circuitBreaker, fallback })`
|
|
396
|
-
- 1 tool dispatch primitive — `ToolProvider` (sync OR async) — `staticTools` · `gatedTools` · `skillScopedTools` · custom `
|
|
399
|
+
- 1 tool dispatch primitive — `ToolProvider` (sync OR async) — `staticTools` · `gatedTools` · `skillScopedTools` · or a custom `ToolProvider` that discovers over hubs / MCP / per-tenant catalogs
|
|
397
400
|
|
|
398
401
|
**LLM providers** (7)
|
|
399
402
|
|
|
@@ -441,6 +444,18 @@ Or jump into the [examples gallery](https://github.com/footprintjs/agentfootprin
|
|
|
441
444
|
|
|
442
445
|
---
|
|
443
446
|
|
|
447
|
+
## Tree-shakeable & ESM-first
|
|
448
|
+
|
|
449
|
+
Import one thing, ship one thing. agentfootprint is built so your bundle grows only with what you actually use:
|
|
450
|
+
|
|
451
|
+
- **Dual build, true ESM.** Ships CommonJS (`require`) **and** real ECMAScript Modules (`import`) with TypeScript types. The ESM build is `type:module` with explicit `.js` import extensions, so it loads as true ESM under Node, Vite, Next, Deno, and Bun — no shims.
|
|
452
|
+
- **Per-file modules + honest `sideEffects`.** The dist is emitted file-by-file (never pre-bundled), so bundlers drop every export you don't touch. A small `import { defineTool }` doesn't pull in the Agent runtime, injection engine, memory stores, or LLM providers.
|
|
453
|
+
- **Subpath exports + lazy peer-deps.** Heavyweight integrations live behind their own subpaths and load their SDK **only when you instantiate them** — importing agentfootprint never bundles `@anthropic-ai/sdk`, `ioredis`, the AWS SDKs, or the MCP SDK unless you actually use that adapter.
|
|
454
|
+
|
|
455
|
+
**Proven, not promised.** A CI smoke test bundles a minimal `import { defineTool }` and asserts the Agent runtime, injection engine, memory stores, and providers are pruned; a second test loads the main barrel and every subpath as true ESM and verifies the lazy-adapter loader works under ESM (`createRequire`, not a bare `require`). See [`test/esm-packaging.test.ts`](test/esm-packaging.test.ts).
|
|
456
|
+
|
|
457
|
+
---
|
|
458
|
+
|
|
444
459
|
## Built on
|
|
445
460
|
|
|
446
461
|
[footprintjs](https://github.com/footprintjs/footPrint) — the flowchart pattern for backend code. agentfootprint's decision-evidence capture, narrative recording, and time-travel checkpointing are footprintjs primitives at the runtime layer.
|
|
@@ -9,11 +9,12 @@
|
|
|
9
9
|
* Emits: N/A.
|
|
10
10
|
*
|
|
11
11
|
* @example
|
|
12
|
+
* const kind = (process.env.LLM_PROVIDER ?? 'anthropic') as ProviderKind;
|
|
12
13
|
* const provider = createProvider({
|
|
13
|
-
* kind
|
|
14
|
+
* kind,
|
|
14
15
|
* apiKey: process.env.LLM_API_KEY,
|
|
15
16
|
* defaultModel: process.env.LLM_MODEL,
|
|
16
|
-
* });
|
|
17
|
+
* } as CreateProviderOptions);
|
|
17
18
|
*
|
|
18
19
|
* For provider-specific options (Bedrock region, Ollama host, Browser
|
|
19
20
|
* apiUrl, etc.) construct the underlying factory directly — this
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createProvider.js","sourceRoot":"","sources":["../../../src/adapters/llm/createProvider.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"createProvider.js","sourceRoot":"","sources":["../../../src/adapters/llm/createProvider.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;AAGH,uDAAmE;AACnE,iEAAkF;AAClF,2DAAiF;AACjF,6DAA4E;AAC5E,+EAGuC;AACvC,yEAA8F;AA2B9F;;GAEG;AACH,SAAgB,cAAc,CAAC,OAA8B;IAC3D,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACrB,KAAK,MAAM;YACT,OAAO,IAAA,sBAAI,EAAC,OAAO,CAAC,CAAC;QACvB,KAAK,WAAW;YACd,OAAO,IAAA,gCAAS,EAAC,OAAO,CAAC,CAAC;QAC5B,KAAK,QAAQ;YACX,OAAO,IAAA,0BAAM,EAAC,OAAO,CAAC,CAAC;QACzB,KAAK,QAAQ;YACX,OAAO,IAAA,0BAAM,EAAC,OAAO,CAAC,CAAC;QACzB,KAAK,SAAS;YACZ,OAAO,IAAA,4BAAO,EAAC,OAAO,CAAC,CAAC;QAC1B,KAAK,mBAAmB;YACtB,OAAO,IAAA,8CAAgB,EAAC,OAAO,CAAC,CAAC;QACnC,KAAK,gBAAgB;YACnB,OAAO,IAAA,wCAAa,EAAC,OAAO,CAAC,CAAC;QAChC,OAAO,CAAC,CAAC,CAAC;YACR,sEAAsE;YACtE,MAAM,WAAW,GAAU,OAAO,CAAC;YACnC,MAAM,IAAI,KAAK,CACb,gCAAgC,IAAI,CAAC,SAAS,CAAE,WAAgC,CAAC,IAAI,CAAC,EAAE,CACzF,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAxBD,wCAwBC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentcore.js","sourceRoot":"","sources":["../../../src/adapters/observability/agentcore.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"agentcore.js","sourceRoot":"","sources":["../../../src/adapters/observability/agentcore.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;;;AAIH,mDAGyB;AAWzB;;;;;GAKG;AACH,SAAgB,sBAAsB,CAAC,IAAmC;IACxE,OAAO,IAAA,6CAA6B,EAAC,IAAI,EAAE,WAAW,CAAC,CAAC;AAC1D,CAAC;AAFD,wDAEC"}
|
|
@@ -38,13 +38,13 @@
|
|
|
38
38
|
*
|
|
39
39
|
* @example Single-stage flowchart as a tool
|
|
40
40
|
* import { flowChart } from 'footprintjs';
|
|
41
|
-
* import { flowchartAsTool } from 'agentfootprint';
|
|
41
|
+
* import { Agent, flowchartAsTool } from 'agentfootprint';
|
|
42
42
|
*
|
|
43
|
-
* const refundChart = flowChart<{
|
|
43
|
+
* const refundChart = flowChart<{ refundId: string }>(
|
|
44
44
|
* 'RefundFlow',
|
|
45
45
|
* async (scope) => {
|
|
46
|
-
* const
|
|
47
|
-
* scope.refundId =
|
|
46
|
+
* const args = scope.$getArgs<{ orderId: string; reason: string }>();
|
|
47
|
+
* scope.refundId = await refundService.process(args.orderId);
|
|
48
48
|
* },
|
|
49
49
|
* 'refund-flow',
|
|
50
50
|
* ).build();
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
* JSON.stringify({ refundId: snapshot.values.refundId, status: 'processed' }),
|
|
66
66
|
* });
|
|
67
67
|
*
|
|
68
|
-
* agent.tool(refundTool);
|
|
68
|
+
* const agent = Agent.create({ provider }).tool(refundTool).build();
|
|
69
69
|
*
|
|
70
70
|
* @example Multi-stage flowchart with decide() + recorders
|
|
71
71
|
* const triageChart = flowChart<TriageState>('Triage', validateInput, 'validate')
|
|
@@ -8,11 +8,12 @@
|
|
|
8
8
|
* Emits: N/A.
|
|
9
9
|
*
|
|
10
10
|
* @example
|
|
11
|
+
* const kind = (process.env.LLM_PROVIDER ?? 'anthropic') as ProviderKind;
|
|
11
12
|
* const provider = createProvider({
|
|
12
|
-
* kind
|
|
13
|
+
* kind,
|
|
13
14
|
* apiKey: process.env.LLM_API_KEY,
|
|
14
15
|
* defaultModel: process.env.LLM_MODEL,
|
|
15
|
-
* });
|
|
16
|
+
* } as CreateProviderOptions);
|
|
16
17
|
*
|
|
17
18
|
* For provider-specific options (Bedrock region, Ollama host, Browser
|
|
18
19
|
* apiUrl, etc.) construct the underlying factory directly — this
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createProvider.js","sourceRoot":"","sources":["../../../../src/adapters/llm/createProvider.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"createProvider.js","sourceRoot":"","sources":["../../../../src/adapters/llm/createProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,EAAE,IAAI,EAA4B,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,SAAS,EAAiC,MAAM,wBAAwB,CAAC;AAClF,OAAO,EAAE,MAAM,EAAE,MAAM,EAA8B,MAAM,qBAAqB,CAAC;AACjF,OAAO,EAAE,OAAO,EAA+B,MAAM,sBAAsB,CAAC;AAC5E,OAAO,EACL,gBAAgB,GAEjB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,aAAa,EAAqC,MAAM,4BAA4B,CAAC;AA2B9F;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,OAA8B;IAC3D,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACrB,KAAK,MAAM;YACT,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC;QACvB,KAAK,WAAW;YACd,OAAO,SAAS,CAAC,OAAO,CAAC,CAAC;QAC5B,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC;QACzB,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC;QACzB,KAAK,SAAS;YACZ,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC;QAC1B,KAAK,mBAAmB;YACtB,OAAO,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACnC,KAAK,gBAAgB;YACnB,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC;QAChC,OAAO,CAAC,CAAC,CAAC;YACR,sEAAsE;YACtE,MAAM,WAAW,GAAU,OAAO,CAAC;YACnC,MAAM,IAAI,KAAK,CACb,gCAAgC,IAAI,CAAC,SAAS,CAAE,WAAgC,CAAC,IAAI,CAAC,EAAE,CACzF,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentcore.js","sourceRoot":"","sources":["../../../../src/adapters/observability/agentcore.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"agentcore.js","sourceRoot":"","sources":["../../../../src/adapters/observability/agentcore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAIH,OAAO,EACL,6BAA6B,GAE9B,MAAM,iBAAiB,CAAC;AAWzB;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAmC;IACxE,OAAO,6BAA6B,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;AAC1D,CAAC"}
|
|
@@ -37,13 +37,13 @@
|
|
|
37
37
|
*
|
|
38
38
|
* @example Single-stage flowchart as a tool
|
|
39
39
|
* import { flowChart } from 'footprintjs';
|
|
40
|
-
* import { flowchartAsTool } from 'agentfootprint';
|
|
40
|
+
* import { Agent, flowchartAsTool } from 'agentfootprint';
|
|
41
41
|
*
|
|
42
|
-
* const refundChart = flowChart<{
|
|
42
|
+
* const refundChart = flowChart<{ refundId: string }>(
|
|
43
43
|
* 'RefundFlow',
|
|
44
44
|
* async (scope) => {
|
|
45
|
-
* const
|
|
46
|
-
* scope.refundId =
|
|
45
|
+
* const args = scope.$getArgs<{ orderId: string; reason: string }>();
|
|
46
|
+
* scope.refundId = await refundService.process(args.orderId);
|
|
47
47
|
* },
|
|
48
48
|
* 'refund-flow',
|
|
49
49
|
* ).build();
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
* JSON.stringify({ refundId: snapshot.values.refundId, status: 'processed' }),
|
|
65
65
|
* });
|
|
66
66
|
*
|
|
67
|
-
* agent.tool(refundTool);
|
|
67
|
+
* const agent = Agent.create({ provider }).tool(refundTool).build();
|
|
68
68
|
*
|
|
69
69
|
* @example Multi-stage flowchart with decide() + recorders
|
|
70
70
|
* const triageChart = flowChart<TriageState>('Triage', validateInput, 'validate')
|