agentic-flow 1.8.11 → 1.8.13

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 (31) hide show
  1. package/dist/cli/federation-cli.d.ts +53 -0
  2. package/dist/cli/federation-cli.js +431 -0
  3. package/dist/cli-proxy.js +28 -1
  4. package/dist/federation/EphemeralAgent.js +258 -0
  5. package/dist/federation/FederationHub.js +283 -0
  6. package/dist/federation/FederationHubClient.js +212 -0
  7. package/dist/federation/FederationHubServer.js +436 -0
  8. package/dist/federation/SecurityManager.js +191 -0
  9. package/dist/federation/debug/agent-debug-stream.js +474 -0
  10. package/dist/federation/debug/debug-stream.js +419 -0
  11. package/dist/federation/index.js +12 -0
  12. package/dist/federation/integrations/realtime-federation.js +404 -0
  13. package/dist/federation/integrations/supabase-adapter-debug.js +400 -0
  14. package/dist/federation/integrations/supabase-adapter.js +258 -0
  15. package/dist/utils/cli.js +5 -0
  16. package/docs/architecture/FEDERATION-DATA-LIFECYCLE.md +520 -0
  17. package/docs/federation/AGENT-DEBUG-STREAMING.md +403 -0
  18. package/docs/federation/DEBUG-STREAMING-COMPLETE.md +432 -0
  19. package/docs/federation/DEBUG-STREAMING.md +537 -0
  20. package/docs/federation/DEPLOYMENT-VALIDATION-SUCCESS.md +394 -0
  21. package/docs/federation/DOCKER-FEDERATION-DEEP-REVIEW.md +478 -0
  22. package/docs/issues/ISSUE-SUPABASE-INTEGRATION.md +536 -0
  23. package/docs/supabase/IMPLEMENTATION-SUMMARY.md +498 -0
  24. package/docs/supabase/INDEX.md +358 -0
  25. package/docs/supabase/QUICKSTART.md +365 -0
  26. package/docs/supabase/README.md +318 -0
  27. package/docs/supabase/SUPABASE-REALTIME-FEDERATION.md +575 -0
  28. package/docs/supabase/TEST-REPORT.md +446 -0
  29. package/docs/supabase/migrations/001_create_federation_tables.sql +339 -0
  30. package/docs/validation/reports/REGRESSION-TEST-V1.8.11.md +456 -0
  31. package/package.json +4 -1
@@ -0,0 +1,404 @@
1
+ /**
2
+ * Real-Time Federation System using Supabase
3
+ *
4
+ * Leverages Supabase Real-Time for:
5
+ * - Live agent coordination
6
+ * - Instant memory synchronization
7
+ * - Real-time presence tracking
8
+ * - Collaborative multi-agent workflows
9
+ * - Event-driven agent communication
10
+ */
11
+ import { createClient } from '@supabase/supabase-js';
12
+ export class RealtimeFederationHub {
13
+ client;
14
+ config;
15
+ channels = new Map();
16
+ presenceChannel;
17
+ agentId;
18
+ tenantId;
19
+ heartbeatInterval;
20
+ eventHandlers = new Map();
21
+ constructor(config, agentId, tenantId = 'default') {
22
+ this.config = config;
23
+ this.agentId = agentId;
24
+ this.tenantId = tenantId;
25
+ const key = config.serviceRoleKey || config.anonKey;
26
+ this.client = createClient(config.url, key, {
27
+ realtime: {
28
+ params: {
29
+ eventsPerSecond: config.broadcastLatency === 'low' ? 10 : 2,
30
+ },
31
+ },
32
+ });
33
+ }
34
+ /**
35
+ * Initialize real-time federation
36
+ */
37
+ async initialize() {
38
+ console.log('🌐 Initializing Real-Time Federation Hub...');
39
+ console.log(` Agent: ${this.agentId}`);
40
+ console.log(` Tenant: ${this.tenantId}`);
41
+ // Set up presence tracking
42
+ await this.setupPresence();
43
+ // Set up memory sync channel
44
+ if (this.config.memorySync !== false) {
45
+ await this.setupMemorySync();
46
+ }
47
+ // Set up coordination channel
48
+ await this.setupCoordination();
49
+ // Start heartbeat
50
+ this.startHeartbeat();
51
+ console.log('✅ Real-Time Federation Hub Active');
52
+ }
53
+ /**
54
+ * Set up presence tracking for all agents in tenant
55
+ */
56
+ async setupPresence() {
57
+ const channelName = `presence:${this.tenantId}`;
58
+ this.presenceChannel = this.client.channel(channelName, {
59
+ config: {
60
+ presence: {
61
+ key: this.agentId,
62
+ },
63
+ },
64
+ });
65
+ // Track agent join
66
+ this.presenceChannel.on('presence', { event: 'join' }, ({ key, newPresences }) => {
67
+ console.log(`🟢 Agent joined: ${key}`);
68
+ this.emit('agent:join', { agent_id: key, presences: newPresences });
69
+ });
70
+ // Track agent leave
71
+ this.presenceChannel.on('presence', { event: 'leave' }, ({ key, leftPresences }) => {
72
+ console.log(`🔴 Agent left: ${key}`);
73
+ this.emit('agent:leave', { agent_id: key, presences: leftPresences });
74
+ });
75
+ // Track agent sync (periodic updates)
76
+ this.presenceChannel.on('presence', { event: 'sync' }, () => {
77
+ const state = this.presenceChannel.presenceState();
78
+ this.emit('agents:sync', { agents: this.getActiveAgents(state) });
79
+ });
80
+ // Subscribe and track presence
81
+ await this.presenceChannel.subscribe(async (status) => {
82
+ if (status === 'SUBSCRIBED') {
83
+ await this.presenceChannel.track({
84
+ agent_id: this.agentId,
85
+ tenant_id: this.tenantId,
86
+ status: 'online',
87
+ started_at: new Date().toISOString(),
88
+ last_heartbeat: new Date().toISOString(),
89
+ });
90
+ }
91
+ });
92
+ }
93
+ /**
94
+ * Set up real-time memory synchronization
95
+ */
96
+ async setupMemorySync() {
97
+ const channelName = `memories:${this.tenantId}`;
98
+ const channel = this.client.channel(channelName);
99
+ // Listen for new memories from database
100
+ channel
101
+ .on('postgres_changes', {
102
+ event: 'INSERT',
103
+ schema: 'public',
104
+ table: 'agent_memories',
105
+ filter: `tenant_id=eq.${this.tenantId}`,
106
+ }, (payload) => {
107
+ const memory = {
108
+ type: 'memory_added',
109
+ tenant_id: payload.new.tenant_id,
110
+ agent_id: payload.new.agent_id,
111
+ session_id: payload.new.session_id,
112
+ content: payload.new.content,
113
+ embedding: payload.new.embedding,
114
+ metadata: payload.new.metadata,
115
+ timestamp: payload.new.created_at,
116
+ };
117
+ this.emit('memory:added', memory);
118
+ })
119
+ .on('postgres_changes', {
120
+ event: 'UPDATE',
121
+ schema: 'public',
122
+ table: 'agent_memories',
123
+ filter: `tenant_id=eq.${this.tenantId}`,
124
+ }, (payload) => {
125
+ const memory = {
126
+ type: 'memory_updated',
127
+ tenant_id: payload.new.tenant_id,
128
+ agent_id: payload.new.agent_id,
129
+ session_id: payload.new.session_id,
130
+ content: payload.new.content,
131
+ embedding: payload.new.embedding,
132
+ metadata: payload.new.metadata,
133
+ timestamp: new Date().toISOString(),
134
+ };
135
+ this.emit('memory:updated', memory);
136
+ });
137
+ await channel.subscribe();
138
+ this.channels.set('memory-sync', channel);
139
+ console.log('💾 Real-time memory sync enabled');
140
+ }
141
+ /**
142
+ * Set up coordination channel for agent-to-agent communication
143
+ */
144
+ async setupCoordination() {
145
+ const channelName = `coordination:${this.tenantId}`;
146
+ const channel = this.client.channel(channelName);
147
+ // Listen for broadcast messages
148
+ channel.on('broadcast', { event: 'coordination' }, ({ payload }) => {
149
+ const message = payload;
150
+ // Only process if message is for us or broadcast
151
+ if (!message.to_agent || message.to_agent === this.agentId) {
152
+ this.emit('message:received', message);
153
+ // Emit specific event types
154
+ this.emit(`message:${message.type}`, message);
155
+ }
156
+ });
157
+ await channel.subscribe();
158
+ this.channels.set('coordination', channel);
159
+ console.log('📡 Agent coordination channel active');
160
+ }
161
+ /**
162
+ * Broadcast message to all agents in tenant
163
+ */
164
+ async broadcast(type, payload) {
165
+ const channel = this.channels.get('coordination');
166
+ if (!channel) {
167
+ throw new Error('Coordination channel not initialized');
168
+ }
169
+ const message = {
170
+ from_agent: this.agentId,
171
+ type,
172
+ payload,
173
+ timestamp: new Date().toISOString(),
174
+ };
175
+ await channel.send({
176
+ type: 'broadcast',
177
+ event: 'coordination',
178
+ payload: message,
179
+ });
180
+ }
181
+ /**
182
+ * Send direct message to specific agent
183
+ */
184
+ async sendMessage(toAgent, type, payload) {
185
+ const channel = this.channels.get('coordination');
186
+ if (!channel) {
187
+ throw new Error('Coordination channel not initialized');
188
+ }
189
+ const message = {
190
+ from_agent: this.agentId,
191
+ to_agent: toAgent,
192
+ type,
193
+ payload,
194
+ timestamp: new Date().toISOString(),
195
+ };
196
+ await channel.send({
197
+ type: 'broadcast',
198
+ event: 'coordination',
199
+ payload: message,
200
+ });
201
+ }
202
+ /**
203
+ * Assign task to another agent
204
+ */
205
+ async assignTask(task) {
206
+ await this.sendMessage(task.assigned_to, 'task_assignment', task);
207
+ console.log(`📋 Task assigned: ${task.task_id} → ${task.assigned_to}`);
208
+ }
209
+ /**
210
+ * Report task completion
211
+ */
212
+ async reportTaskComplete(taskId, result) {
213
+ await this.broadcast('task_complete', {
214
+ task_id: taskId,
215
+ result,
216
+ completed_by: this.agentId,
217
+ });
218
+ console.log(`✅ Task completed: ${taskId}`);
219
+ }
220
+ /**
221
+ * Request help from other agents
222
+ */
223
+ async requestHelp(problem, context) {
224
+ await this.broadcast('request_help', {
225
+ problem,
226
+ context,
227
+ from: this.agentId,
228
+ });
229
+ console.log(`🆘 Help requested: ${problem}`);
230
+ }
231
+ /**
232
+ * Share knowledge with other agents
233
+ */
234
+ async shareKnowledge(knowledge, metadata) {
235
+ await this.broadcast('share_knowledge', {
236
+ knowledge,
237
+ metadata,
238
+ from: this.agentId,
239
+ });
240
+ console.log(`💡 Knowledge shared: ${knowledge.substring(0, 50)}...`);
241
+ }
242
+ /**
243
+ * Update agent status
244
+ */
245
+ async updateStatus(status, task) {
246
+ if (!this.presenceChannel)
247
+ return;
248
+ await this.presenceChannel.track({
249
+ agent_id: this.agentId,
250
+ tenant_id: this.tenantId,
251
+ status,
252
+ task,
253
+ last_heartbeat: new Date().toISOString(),
254
+ });
255
+ await this.broadcast('status_update', {
256
+ agent_id: this.agentId,
257
+ status,
258
+ task,
259
+ });
260
+ }
261
+ /**
262
+ * Get list of active agents
263
+ */
264
+ getActiveAgents(presenceState) {
265
+ if (!this.presenceChannel)
266
+ return [];
267
+ const state = presenceState || this.presenceChannel.presenceState();
268
+ const agents = [];
269
+ for (const [agentId, presences] of Object.entries(state)) {
270
+ const presence = presences[0];
271
+ agents.push({
272
+ agent_id: agentId,
273
+ tenant_id: presence.tenant_id,
274
+ status: presence.status,
275
+ task: presence.task,
276
+ started_at: presence.started_at,
277
+ last_heartbeat: presence.last_heartbeat,
278
+ metadata: presence.metadata,
279
+ });
280
+ }
281
+ return agents;
282
+ }
283
+ /**
284
+ * Start heartbeat to maintain presence
285
+ */
286
+ startHeartbeat() {
287
+ const interval = this.config.presenceHeartbeat || 30000;
288
+ this.heartbeatInterval = setInterval(async () => {
289
+ if (this.presenceChannel) {
290
+ await this.presenceChannel.track({
291
+ agent_id: this.agentId,
292
+ tenant_id: this.tenantId,
293
+ last_heartbeat: new Date().toISOString(),
294
+ });
295
+ }
296
+ }, interval);
297
+ }
298
+ /**
299
+ * Stop heartbeat
300
+ */
301
+ stopHeartbeat() {
302
+ if (this.heartbeatInterval) {
303
+ clearInterval(this.heartbeatInterval);
304
+ this.heartbeatInterval = undefined;
305
+ }
306
+ }
307
+ /**
308
+ * Subscribe to events
309
+ */
310
+ on(event, handler) {
311
+ if (!this.eventHandlers.has(event)) {
312
+ this.eventHandlers.set(event, new Set());
313
+ }
314
+ this.eventHandlers.get(event).add(handler);
315
+ }
316
+ /**
317
+ * Unsubscribe from events
318
+ */
319
+ off(event, handler) {
320
+ const handlers = this.eventHandlers.get(event);
321
+ if (handlers) {
322
+ handlers.delete(handler);
323
+ }
324
+ }
325
+ /**
326
+ * Emit event to handlers
327
+ */
328
+ emit(event, data) {
329
+ const handlers = this.eventHandlers.get(event);
330
+ if (handlers) {
331
+ handlers.forEach((handler) => {
332
+ try {
333
+ handler(data);
334
+ }
335
+ catch (error) {
336
+ console.error(`Error in event handler for ${event}:`, error);
337
+ }
338
+ });
339
+ }
340
+ }
341
+ /**
342
+ * Get real-time statistics
343
+ */
344
+ async getStats() {
345
+ const activeAgents = this.getActiveAgents();
346
+ return {
347
+ tenant_id: this.tenantId,
348
+ agent_id: this.agentId,
349
+ active_agents: activeAgents.length,
350
+ agents: activeAgents,
351
+ channels: Array.from(this.channels.keys()),
352
+ heartbeat_interval: this.config.presenceHeartbeat || 30000,
353
+ memory_sync: this.config.memorySync !== false,
354
+ timestamp: new Date().toISOString(),
355
+ };
356
+ }
357
+ /**
358
+ * Shutdown and cleanup
359
+ */
360
+ async shutdown() {
361
+ console.log('🛑 Shutting down Real-Time Federation Hub...');
362
+ // Stop heartbeat
363
+ this.stopHeartbeat();
364
+ // Update status to offline
365
+ if (this.presenceChannel) {
366
+ await this.presenceChannel.track({
367
+ agent_id: this.agentId,
368
+ tenant_id: this.tenantId,
369
+ status: 'offline',
370
+ });
371
+ await this.presenceChannel.untrack();
372
+ }
373
+ // Unsubscribe from all channels
374
+ for (const [name, channel] of this.channels) {
375
+ await channel.unsubscribe();
376
+ console.log(` Unsubscribed from ${name}`);
377
+ }
378
+ if (this.presenceChannel) {
379
+ await this.presenceChannel.unsubscribe();
380
+ }
381
+ this.channels.clear();
382
+ this.eventHandlers.clear();
383
+ console.log('✅ Real-Time Federation Hub shutdown complete');
384
+ }
385
+ }
386
+ /**
387
+ * Create real-time federation hub from environment
388
+ */
389
+ export function createRealtimeHub(agentId, tenantId = 'default') {
390
+ const url = process.env.SUPABASE_URL;
391
+ const anonKey = process.env.SUPABASE_ANON_KEY;
392
+ const serviceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
393
+ if (!url || !anonKey) {
394
+ throw new Error('Missing Supabase credentials. Set SUPABASE_URL and SUPABASE_ANON_KEY');
395
+ }
396
+ return new RealtimeFederationHub({
397
+ url,
398
+ anonKey,
399
+ serviceRoleKey,
400
+ presenceHeartbeat: parseInt(process.env.FEDERATION_HEARTBEAT_INTERVAL || '30000'),
401
+ memorySync: process.env.FEDERATION_MEMORY_SYNC !== 'false',
402
+ broadcastLatency: process.env.FEDERATION_BROADCAST_LATENCY || 'low',
403
+ }, agentId, tenantId);
404
+ }