agentic-flow 1.8.11 → 1.8.14
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/CHANGELOG.md +58 -0
- package/dist/agents/claudeAgentDirect.js +168 -0
- package/dist/cli/federation-cli.d.ts +53 -0
- package/dist/cli/federation-cli.js +431 -0
- package/dist/cli-proxy.js +32 -4
- package/dist/federation/EphemeralAgent.js +258 -0
- package/dist/federation/FederationHub.js +283 -0
- package/dist/federation/FederationHubClient.js +212 -0
- package/dist/federation/FederationHubServer.js +436 -0
- package/dist/federation/SecurityManager.js +191 -0
- package/dist/federation/debug/agent-debug-stream.js +474 -0
- package/dist/federation/debug/debug-stream.js +419 -0
- package/dist/federation/index.js +12 -0
- package/dist/federation/integrations/realtime-federation.js +404 -0
- package/dist/federation/integrations/supabase-adapter-debug.js +400 -0
- package/dist/federation/integrations/supabase-adapter.js +258 -0
- package/dist/utils/cli.js +5 -0
- package/docs/architecture/FEDERATION-DATA-LIFECYCLE.md +520 -0
- package/docs/federation/AGENT-DEBUG-STREAMING.md +403 -0
- package/docs/federation/DEBUG-STREAMING-COMPLETE.md +432 -0
- package/docs/federation/DEBUG-STREAMING.md +537 -0
- package/docs/federation/DEPLOYMENT-VALIDATION-SUCCESS.md +394 -0
- package/docs/federation/DOCKER-FEDERATION-DEEP-REVIEW.md +478 -0
- package/docs/issues/ISSUE-SUPABASE-INTEGRATION.md +536 -0
- package/docs/releases/RELEASE-v1.8.13.md +426 -0
- package/docs/supabase/IMPLEMENTATION-SUMMARY.md +498 -0
- package/docs/supabase/INDEX.md +358 -0
- package/docs/supabase/QUICKSTART.md +365 -0
- package/docs/supabase/README.md +318 -0
- package/docs/supabase/SUPABASE-REALTIME-FEDERATION.md +575 -0
- package/docs/supabase/TEST-REPORT.md +446 -0
- package/docs/supabase/migrations/001_create_federation_tables.sql +339 -0
- package/docs/validation/reports/REGRESSION-TEST-V1.8.11.md +456 -0
- package/package.json +4 -1
- package/wasm/reasoningbank/reasoningbank_wasm_bg.js +2 -2
- package/wasm/reasoningbank/reasoningbank_wasm_bg.wasm +0 -0
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
# Federation Data Lifecycle: Persistent vs Ephemeral Storage
|
|
2
|
+
|
|
3
|
+
## Architecture Overview
|
|
4
|
+
|
|
5
|
+
The federation system uses a **hub-and-spoke** model with **persistent central storage** and **ephemeral agent storage**.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
┌─────────────────────────────────────────────────────────┐
|
|
9
|
+
│ FEDERATION HUB (PERSISTENT) │
|
|
10
|
+
│ │
|
|
11
|
+
│ ┌────────────────────┐ ┌─────────────────────────┐ │
|
|
12
|
+
│ │ SQLite DB │ │ AgentDB │ │
|
|
13
|
+
│ │ (Metadata) │ │ (Vector Memory) │ │
|
|
14
|
+
│ │ │ │ │ │
|
|
15
|
+
│ │ • Episode metadata │ │ • Vector embeddings │ │
|
|
16
|
+
│ │ • Agent registry │ │ • HNSW index │ │
|
|
17
|
+
│ │ • Change log │ │ • Semantic search │ │
|
|
18
|
+
│ │ • Tenant isolation │ │ • Pattern storage │ │
|
|
19
|
+
│ └────────────────────┘ └─────────────────────────┘ │
|
|
20
|
+
│ │
|
|
21
|
+
│ Storage: /data/hub.db and /data/hub-agentdb.db │
|
|
22
|
+
│ Lifetime: PERMANENT (until manually deleted) │
|
|
23
|
+
└─────────────────────────────────────────────────────────┘
|
|
24
|
+
↑
|
|
25
|
+
│ WebSocket Sync
|
|
26
|
+
┌─────────────────┼─────────────────┐
|
|
27
|
+
│ │ │
|
|
28
|
+
↓ ↓ ↓
|
|
29
|
+
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
|
30
|
+
│ Agent 1 │ │ Agent 2 │ │ Agent 3 │
|
|
31
|
+
│ (Ephemeral) │ │ (Ephemeral) │ │ (Ephemeral) │
|
|
32
|
+
│ │ │ │ │ │
|
|
33
|
+
│ Local AgentDB│ │ Local AgentDB│ │ Local AgentDB│
|
|
34
|
+
│ Storage: │ │ Storage: │ │ Storage: │
|
|
35
|
+
│ :memory: │ │ :memory: │ │ :memory: │
|
|
36
|
+
│ │ │ │ │ │
|
|
37
|
+
│ Lifetime: │ │ Lifetime: │ │ Lifetime: │
|
|
38
|
+
│ 5s - 15min │ │ 5s - 15min │ │ 5s - 15min │
|
|
39
|
+
└──────────────┘ └──────────────┘ └──────────────┘
|
|
40
|
+
↓ ↓ ↓
|
|
41
|
+
DESTROYED DESTROYED DESTROYED
|
|
42
|
+
(RAM freed) (RAM freed) (RAM freed)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Data Flow: Complete Lifecycle
|
|
48
|
+
|
|
49
|
+
### Phase 1: Agent Spawns
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
// Agent spawns with ephemeral memory
|
|
53
|
+
const agent = await EphemeralAgent.spawn({
|
|
54
|
+
tenantId: 'acme-corp',
|
|
55
|
+
lifetime: 300, // 5 minutes
|
|
56
|
+
hubEndpoint: 'ws://hub:8443'
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Local AgentDB created in memory
|
|
60
|
+
agent.agentDB = new AgentDB({ path: ':memory:' });
|
|
61
|
+
|
|
62
|
+
// Connect to hub
|
|
63
|
+
await agent.connect();
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Storage State:**
|
|
67
|
+
- Hub: Empty (or has old memories from previous agents)
|
|
68
|
+
- Agent: Empty `:memory:` database
|
|
69
|
+
|
|
70
|
+
### Phase 2: Agent Pulls Memories from Hub
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
await agent.execute(async (db) => {
|
|
74
|
+
// PULL: Agent requests memories from hub
|
|
75
|
+
const memories = await agent.queryMemories('task-name', 10);
|
|
76
|
+
|
|
77
|
+
// Hub sends back all relevant memories from past agents
|
|
78
|
+
// Agent stores them locally for fast semantic search
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Storage State:**
|
|
83
|
+
- Hub: Contains 1000 memories from previous agents (PERSISTENT)
|
|
84
|
+
- Agent: Downloaded 10 relevant memories to local `:memory:` (TEMPORARY)
|
|
85
|
+
|
|
86
|
+
**Data Transfer:**
|
|
87
|
+
```
|
|
88
|
+
Hub (Disk: 1000 episodes)
|
|
89
|
+
→ WebSocket
|
|
90
|
+
→ Agent (RAM: 10 relevant episodes)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Phase 3: Agent Works and Learns
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
await agent.execute(async (db) => {
|
|
97
|
+
// Agent uses memories to inform decisions
|
|
98
|
+
const context = await agent.queryMemories('similar-task');
|
|
99
|
+
|
|
100
|
+
// Agent performs work
|
|
101
|
+
const result = await processTask(context);
|
|
102
|
+
|
|
103
|
+
// Agent stores NEW learning locally
|
|
104
|
+
await agent.storeEpisode({
|
|
105
|
+
task: 'task-name',
|
|
106
|
+
input: 'data',
|
|
107
|
+
output: result,
|
|
108
|
+
reward: 0.95
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Storage State:**
|
|
114
|
+
- Hub: Still 1000 memories (not updated yet)
|
|
115
|
+
- Agent: 10 old + 1 new = 11 memories in RAM
|
|
116
|
+
|
|
117
|
+
### Phase 4: Agent Syncs to Hub (PUSH)
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
// Agent pushes new memories to hub
|
|
121
|
+
await agent.syncWithHub();
|
|
122
|
+
|
|
123
|
+
// Hub receives and stores permanently
|
|
124
|
+
hub.agentDB.storePattern({
|
|
125
|
+
sessionId: 'acme-corp/agent-001',
|
|
126
|
+
task: 'task-name',
|
|
127
|
+
...episode
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Storage State:**
|
|
132
|
+
- Hub: 1001 memories (NEW memory added to disk) ✅
|
|
133
|
+
- Agent: 11 memories in RAM
|
|
134
|
+
|
|
135
|
+
**Data Transfer:**
|
|
136
|
+
```
|
|
137
|
+
Agent (RAM: 1 new episode)
|
|
138
|
+
→ WebSocket
|
|
139
|
+
→ Hub (Disk: saves permanently)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Phase 5: Agent Expires and Destroys
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
// After 5 minutes (or manual cleanup)
|
|
146
|
+
await agent.destroy();
|
|
147
|
+
|
|
148
|
+
// Local memory is freed
|
|
149
|
+
agent.agentDB.close(); // :memory: database destroyed
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Storage State:**
|
|
153
|
+
- Hub: 1001 memories (PERSISTS on disk) ✅
|
|
154
|
+
- Agent: RAM freed, all local data GONE ❌
|
|
155
|
+
|
|
156
|
+
### Phase 6: New Agent Spawns (Hours/Days Later)
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
// New agent spawns in the future
|
|
160
|
+
const newAgent = await EphemeralAgent.spawn({
|
|
161
|
+
tenantId: 'acme-corp', // Same tenant
|
|
162
|
+
lifetime: 300,
|
|
163
|
+
hubEndpoint: 'ws://hub:8443'
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
await newAgent.execute(async (db) => {
|
|
167
|
+
// NEW agent can access OLD memories!
|
|
168
|
+
const memories = await newAgent.queryMemories('task-name', 10);
|
|
169
|
+
|
|
170
|
+
// Returns memories from previous agents that died hours ago
|
|
171
|
+
console.log(memories.length); // 10 memories (including episode from Agent 1)
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Storage State:**
|
|
176
|
+
- Hub: 1001 memories (still on disk from previous agents) ✅
|
|
177
|
+
- New Agent: Downloads 10 relevant memories from hub (including work from Agent 1)
|
|
178
|
+
|
|
179
|
+
**Key Insight**: Memory outlives the agents! 🎉
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Storage Locations
|
|
184
|
+
|
|
185
|
+
### Hub Storage (PERSISTENT)
|
|
186
|
+
|
|
187
|
+
**SQLite Database: `/data/hub.db`**
|
|
188
|
+
```sql
|
|
189
|
+
CREATE TABLE episodes (
|
|
190
|
+
id INTEGER PRIMARY KEY,
|
|
191
|
+
tenant_id TEXT NOT NULL, -- Tenant isolation
|
|
192
|
+
agent_id TEXT NOT NULL, -- Which agent created this
|
|
193
|
+
session_id TEXT NOT NULL, -- Agent session
|
|
194
|
+
task TEXT NOT NULL, -- Task description
|
|
195
|
+
input TEXT NOT NULL, -- Task input
|
|
196
|
+
output TEXT NOT NULL, -- Task output
|
|
197
|
+
reward REAL NOT NULL, -- Success metric
|
|
198
|
+
created_at INTEGER NOT NULL -- Timestamp
|
|
199
|
+
);
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**AgentDB Database: `/data/hub-agentdb.db`**
|
|
203
|
+
```typescript
|
|
204
|
+
{
|
|
205
|
+
sessionId: 'acme-corp/agent-001', // Tenant prefix for isolation
|
|
206
|
+
task: 'implement-feature',
|
|
207
|
+
embedding: [...384 dimensions...], // Vector for semantic search
|
|
208
|
+
reward: 0.95,
|
|
209
|
+
metadata: {
|
|
210
|
+
tenantId: 'acme-corp',
|
|
211
|
+
agentId: 'agent-001',
|
|
212
|
+
timestamp: 1234567890
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Lifetime**: PERMANENT until:
|
|
218
|
+
- Manually deleted
|
|
219
|
+
- Retention policy applied (e.g., delete after 90 days)
|
|
220
|
+
- Tenant requests data deletion (GDPR)
|
|
221
|
+
|
|
222
|
+
### Agent Storage (EPHEMERAL)
|
|
223
|
+
|
|
224
|
+
**Location**: `:memory:` (RAM only)
|
|
225
|
+
|
|
226
|
+
**Lifetime**: 5 seconds to 15 minutes
|
|
227
|
+
|
|
228
|
+
**Contents**:
|
|
229
|
+
- Downloaded memories from hub
|
|
230
|
+
- Local work in progress
|
|
231
|
+
- Temporary caches
|
|
232
|
+
|
|
233
|
+
**Destroyed when**:
|
|
234
|
+
- Agent reaches `lifetime` expiration
|
|
235
|
+
- Manual `agent.destroy()` call
|
|
236
|
+
- Process crash/restart
|
|
237
|
+
- Container shutdown
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Memory Persistence Guarantees
|
|
242
|
+
|
|
243
|
+
### ✅ What PERSISTS (Survives Agent Death)
|
|
244
|
+
|
|
245
|
+
1. **All Episodes**: Every `storeEpisode()` call that syncs to hub
|
|
246
|
+
2. **Vector Embeddings**: Semantic search index in hub AgentDB
|
|
247
|
+
3. **Metadata**: Agent ID, tenant ID, timestamps, rewards
|
|
248
|
+
4. **Tenant Isolation**: Sessions tagged with tenant prefix
|
|
249
|
+
5. **Change Log**: History of all modifications
|
|
250
|
+
|
|
251
|
+
### ❌ What is LOST (Agent Death)
|
|
252
|
+
|
|
253
|
+
1. **Local Cache**: Downloaded memories in agent's `:memory:` DB
|
|
254
|
+
2. **In-Progress Work**: Anything not yet synced to hub
|
|
255
|
+
3. **Temporary State**: Agent-specific runtime data
|
|
256
|
+
4. **Unsaved Episodes**: Episodes created but not synced
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Sync Timing: When Does Data Persist?
|
|
261
|
+
|
|
262
|
+
### Automatic Sync Points
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
class EphemeralAgent {
|
|
266
|
+
async execute(task) {
|
|
267
|
+
// 1. PRE-SYNC: Pull latest from hub
|
|
268
|
+
await this.syncWithHub(); // Download new memories
|
|
269
|
+
|
|
270
|
+
// 2. WORK: Agent performs task
|
|
271
|
+
const result = await task(this.db);
|
|
272
|
+
|
|
273
|
+
// 3. POST-SYNC: Push new memories to hub
|
|
274
|
+
await this.syncWithHub(); // Upload new episodes ✅
|
|
275
|
+
|
|
276
|
+
return result;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
async destroy() {
|
|
280
|
+
// 4. FINAL SYNC: Ensure everything is saved
|
|
281
|
+
await this.syncWithHub(); // Last chance to save ✅
|
|
282
|
+
|
|
283
|
+
// 5. Local cleanup
|
|
284
|
+
await this.agentDB.close(); // Memory freed
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Manual Sync
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
// Developer can force sync anytime
|
|
293
|
+
await agent.syncWithHub(); // Pushes all local episodes to hub
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**Guarantee**: Any episode stored before `syncWithHub()` is PERMANENT.
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Example: Multi-Generation Learning
|
|
301
|
+
|
|
302
|
+
### Day 1: First Agent
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
// 10:00 AM - Agent 1 spawns
|
|
306
|
+
const agent1 = await EphemeralAgent.spawn({
|
|
307
|
+
tenantId: 'research-team',
|
|
308
|
+
lifetime: 300
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
await agent1.execute(async () => {
|
|
312
|
+
await agent1.storeEpisode({
|
|
313
|
+
task: 'analyze-data',
|
|
314
|
+
input: 'dataset-v1',
|
|
315
|
+
output: 'Found pattern X',
|
|
316
|
+
reward: 0.92
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// 10:05 AM - Agent 1 destroyed
|
|
321
|
+
await agent1.destroy(); // Episode saved to hub ✅
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
**Hub Storage**: 1 episode
|
|
325
|
+
|
|
326
|
+
### Day 2: Second Agent
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
// 9:00 AM (next day) - Agent 2 spawns
|
|
330
|
+
const agent2 = await EphemeralAgent.spawn({
|
|
331
|
+
tenantId: 'research-team', // Same tenant
|
|
332
|
+
lifetime: 300
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
await agent2.execute(async () => {
|
|
336
|
+
// Query memories (finds Agent 1's work from yesterday!)
|
|
337
|
+
const memories = await agent2.queryMemories('analyze-data');
|
|
338
|
+
|
|
339
|
+
console.log(memories[0].output); // "Found pattern X" ✅
|
|
340
|
+
console.log(memories[0].agentId); // "agent-001" (from yesterday)
|
|
341
|
+
|
|
342
|
+
// Build on previous work
|
|
343
|
+
await agent2.storeEpisode({
|
|
344
|
+
task: 'refine-pattern',
|
|
345
|
+
input: 'pattern-x',
|
|
346
|
+
output: 'Confirmed pattern X, found pattern Y',
|
|
347
|
+
reward: 0.96
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
await agent2.destroy();
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
**Hub Storage**: 2 episodes (Agent 1 + Agent 2)
|
|
355
|
+
|
|
356
|
+
### Day 30: Tenth Agent
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
// 30 days later - Agent 10 spawns
|
|
360
|
+
const agent10 = await EphemeralAgent.spawn({
|
|
361
|
+
tenantId: 'research-team',
|
|
362
|
+
lifetime: 300
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
await agent10.execute(async () => {
|
|
366
|
+
// Query all past work
|
|
367
|
+
const memories = await agent10.queryMemories('pattern', 100);
|
|
368
|
+
|
|
369
|
+
console.log(memories.length); // 50+ episodes from 9 previous agents ✅
|
|
370
|
+
|
|
371
|
+
// Agent 10 learns from all past agents' successes
|
|
372
|
+
const bestPatterns = memories
|
|
373
|
+
.filter(m => m.reward > 0.90)
|
|
374
|
+
.map(m => m.output);
|
|
375
|
+
|
|
376
|
+
// Standing on the shoulders of giants 🚀
|
|
377
|
+
});
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
**Hub Storage**: 50+ episodes (cumulative learning)
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## Retention Policies
|
|
385
|
+
|
|
386
|
+
### Default: Infinite Retention
|
|
387
|
+
|
|
388
|
+
Hub stores everything forever unless configured otherwise.
|
|
389
|
+
|
|
390
|
+
### Optional: Time-Based Retention
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
// Delete episodes older than 90 days
|
|
394
|
+
hub.db.prepare(`
|
|
395
|
+
DELETE FROM episodes
|
|
396
|
+
WHERE created_at < ?
|
|
397
|
+
`).run(Date.now() - (90 * 24 * 60 * 60 * 1000));
|
|
398
|
+
|
|
399
|
+
// Delete from AgentDB too
|
|
400
|
+
await hub.agentDB.deleteOldPatterns({ maxAge: 90 * 24 * 60 * 60 });
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### Optional: Reward-Based Retention
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
// Keep only high-reward episodes
|
|
407
|
+
hub.db.prepare(`
|
|
408
|
+
DELETE FROM episodes
|
|
409
|
+
WHERE reward < 0.70
|
|
410
|
+
`).run();
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## Disaster Recovery
|
|
416
|
+
|
|
417
|
+
### Hub Backup
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
# Backup hub databases
|
|
421
|
+
cp /data/hub.db /backup/hub-2025-10-31.db
|
|
422
|
+
cp /data/hub-agentdb.db /backup/hub-agentdb-2025-10-31.db
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### Hub Restore
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
# Restore from backup
|
|
429
|
+
cp /backup/hub-2025-10-31.db /data/hub.db
|
|
430
|
+
cp /backup/hub-agentdb-2025-10-31.db /data/hub-agentdb.db
|
|
431
|
+
|
|
432
|
+
# Restart hub
|
|
433
|
+
docker restart federation-hub
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Agent Recovery
|
|
437
|
+
|
|
438
|
+
**Agents don't need backup** - They're ephemeral by design!
|
|
439
|
+
|
|
440
|
+
If an agent crashes, just spawn a new one:
|
|
441
|
+
|
|
442
|
+
```typescript
|
|
443
|
+
// Old agent crashed (no problem!)
|
|
444
|
+
// agent1 died unexpectedly ❌
|
|
445
|
+
|
|
446
|
+
// Spawn replacement
|
|
447
|
+
const agent2 = await EphemeralAgent.spawn({
|
|
448
|
+
tenantId: 'acme-corp', // Same tenant
|
|
449
|
+
lifetime: 300
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
// New agent has access to ALL old memories ✅
|
|
453
|
+
await agent2.execute(async () => {
|
|
454
|
+
const memories = await agent2.queryMemories('task');
|
|
455
|
+
// Gets memories from crashed agent + all previous agents
|
|
456
|
+
});
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## Production Deployment
|
|
462
|
+
|
|
463
|
+
### Single Hub (Simple)
|
|
464
|
+
|
|
465
|
+
```yaml
|
|
466
|
+
# docker-compose.yml
|
|
467
|
+
services:
|
|
468
|
+
federation-hub:
|
|
469
|
+
image: federation-hub:latest
|
|
470
|
+
volumes:
|
|
471
|
+
- hub-data:/data # PERSISTENT volume
|
|
472
|
+
ports:
|
|
473
|
+
- "8443:8443"
|
|
474
|
+
|
|
475
|
+
volumes:
|
|
476
|
+
hub-data:
|
|
477
|
+
driver: local # Data survives container restarts
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
**Persistence**: Volume survives container restarts ✅
|
|
481
|
+
|
|
482
|
+
### Multi-Hub (High Availability)
|
|
483
|
+
|
|
484
|
+
```
|
|
485
|
+
┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
486
|
+
│ Hub US │────▶│ Hub EU │────▶│ Hub AP │
|
|
487
|
+
│ (Primary)│ │(Replica) │ │(Replica) │
|
|
488
|
+
└──────────┘ └──────────┘ └──────────┘
|
|
489
|
+
│ │ │
|
|
490
|
+
└────────────────┴────────────────┘
|
|
491
|
+
Sync every 5 seconds
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
**Guarantee**: Data replicated across regions ✅
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
## Key Takeaways
|
|
499
|
+
|
|
500
|
+
1. **Hub = Permanent**: All memories stored on disk forever (until manually deleted)
|
|
501
|
+
|
|
502
|
+
2. **Agents = Temporary**: Local databases destroyed after 5-15 minutes
|
|
503
|
+
|
|
504
|
+
3. **Memory Outlives Agents**: New agents can access memories from agents that died hours/days/weeks ago
|
|
505
|
+
|
|
506
|
+
4. **Sync = Persist**: Any episode that syncs to hub is PERMANENT
|
|
507
|
+
|
|
508
|
+
5. **Tenant Isolation**: Memories are isolated by tenant, but persist across all agents in that tenant
|
|
509
|
+
|
|
510
|
+
6. **No Data Loss**: As long as hub is backed up, no memories are lost when agents die
|
|
511
|
+
|
|
512
|
+
7. **Infinite Generations**: Agents can learn from an unlimited chain of previous agents
|
|
513
|
+
|
|
514
|
+
8. **Docker Volumes**: Hub data persists across container restarts if using volumes
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
**Bottom Line**: The federation hub is the "source of truth" - it's a **persistent, centralized database** that outlives all ephemeral agents. Agents come and go, but the hub remembers everything. 🧠
|
|
519
|
+
|
|
520
|
+
This enables **continuous learning** where each new generation of agents builds on the collective knowledge of all previous generations, while maintaining the efficiency benefits of ephemeral, short-lived agents.
|