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,400 @@
1
+ /**
2
+ * Supabase Database Adapter with Debug Streaming
3
+ *
4
+ * Enhanced version of SupabaseFederationAdapter with comprehensive
5
+ * debug logging and performance tracking.
6
+ */
7
+ import { createClient } from '@supabase/supabase-js';
8
+ import { DebugLevel, createDebugStream } from '../debug/debug-stream.js';
9
+ export class SupabaseFederationAdapterDebug {
10
+ client;
11
+ config;
12
+ debug;
13
+ constructor(config) {
14
+ this.config = config;
15
+ // Initialize debug stream
16
+ this.debug = createDebugStream({
17
+ level: config.debug?.level ?? DebugLevel.BASIC,
18
+ output: config.debug?.output ?? 'console',
19
+ format: config.debug?.format ?? 'human',
20
+ outputFile: config.debug?.outputFile,
21
+ });
22
+ const startTime = Date.now();
23
+ // Use service role key for server-side operations
24
+ const key = config.serviceRoleKey || config.anonKey;
25
+ this.client = createClient(config.url, key);
26
+ this.debug.logConnection('client_created', {
27
+ url: config.url,
28
+ hasServiceRole: !!config.serviceRoleKey,
29
+ vectorBackend: config.vectorBackend,
30
+ });
31
+ const duration = Date.now() - startTime;
32
+ this.debug.logTrace('constructor_complete', { duration });
33
+ }
34
+ /**
35
+ * Initialize Supabase schema for federation
36
+ */
37
+ async initialize() {
38
+ const startTime = Date.now();
39
+ this.debug.logConnection('initialize_start', {
40
+ vectorBackend: this.config.vectorBackend,
41
+ });
42
+ try {
43
+ // Check if tables exist
44
+ await this.ensureTables();
45
+ if (this.config.vectorBackend === 'pgvector') {
46
+ await this.ensureVectorExtension();
47
+ }
48
+ const duration = Date.now() - startTime;
49
+ this.debug.logConnection('initialize_complete', { duration }, duration);
50
+ }
51
+ catch (error) {
52
+ const duration = Date.now() - startTime;
53
+ this.debug.logConnection('initialize_error', { duration }, duration, error);
54
+ throw error;
55
+ }
56
+ }
57
+ /**
58
+ * Ensure required tables exist
59
+ */
60
+ async ensureTables() {
61
+ const startTime = Date.now();
62
+ this.debug.logTrace('checking_tables');
63
+ const tables = ['agent_sessions', 'agent_memories', 'agent_tasks', 'agent_events'];
64
+ const results = {};
65
+ for (const table of tables) {
66
+ const tableStart = Date.now();
67
+ try {
68
+ const { data, error } = await this.client
69
+ .from(table)
70
+ .select('id')
71
+ .limit(1);
72
+ const exists = !error || error.code !== 'PGRST116';
73
+ results[table] = exists;
74
+ const tableDuration = Date.now() - tableStart;
75
+ this.debug.logDatabase('table_check', {
76
+ table,
77
+ exists,
78
+ }, tableDuration);
79
+ if (!exists) {
80
+ this.debug.logDatabase('table_missing', { table });
81
+ }
82
+ }
83
+ catch (error) {
84
+ const tableDuration = Date.now() - tableStart;
85
+ this.debug.logDatabase('table_check_error', { table }, tableDuration, error);
86
+ }
87
+ }
88
+ const duration = Date.now() - startTime;
89
+ this.debug.logDatabase('tables_checked', { results }, duration);
90
+ }
91
+ /**
92
+ * Ensure pgvector extension is enabled
93
+ */
94
+ async ensureVectorExtension() {
95
+ const startTime = Date.now();
96
+ this.debug.logTrace('checking_pgvector');
97
+ try {
98
+ const { error } = await this.client.rpc('exec_sql', {
99
+ sql: 'CREATE EXTENSION IF NOT EXISTS vector;'
100
+ });
101
+ const duration = Date.now() - startTime;
102
+ if (error) {
103
+ this.debug.logDatabase('pgvector_check_failed', {
104
+ message: error.message,
105
+ }, duration, error);
106
+ }
107
+ else {
108
+ this.debug.logDatabase('pgvector_ready', {}, duration);
109
+ }
110
+ }
111
+ catch (err) {
112
+ const duration = Date.now() - startTime;
113
+ this.debug.logDatabase('pgvector_error', {}, duration, err);
114
+ }
115
+ }
116
+ /**
117
+ * Store agent memory in Supabase
118
+ */
119
+ async storeMemory(memory) {
120
+ const startTime = Date.now();
121
+ this.debug.logMemory('store_start', memory.agent_id, memory.tenant_id, {
122
+ id: memory.id,
123
+ content_length: memory.content.length,
124
+ has_embedding: !!memory.embedding,
125
+ embedding_dims: memory.embedding?.length,
126
+ });
127
+ try {
128
+ const { error } = await this.client
129
+ .from('agent_memories')
130
+ .insert({
131
+ id: memory.id,
132
+ tenant_id: memory.tenant_id,
133
+ agent_id: memory.agent_id,
134
+ session_id: memory.session_id,
135
+ content: memory.content,
136
+ embedding: memory.embedding,
137
+ metadata: memory.metadata,
138
+ created_at: memory.created_at || new Date().toISOString(),
139
+ expires_at: memory.expires_at,
140
+ });
141
+ const duration = Date.now() - startTime;
142
+ if (error) {
143
+ this.debug.logMemory('store_error', memory.agent_id, memory.tenant_id, {
144
+ error: error.message,
145
+ }, duration);
146
+ throw new Error(`Failed to store memory: ${error.message}`);
147
+ }
148
+ this.debug.logMemory('store_complete', memory.agent_id, memory.tenant_id, {
149
+ id: memory.id,
150
+ }, duration);
151
+ }
152
+ catch (error) {
153
+ const duration = Date.now() - startTime;
154
+ this.debug.logMemory('store_failed', memory.agent_id, memory.tenant_id, {}, duration);
155
+ throw error;
156
+ }
157
+ }
158
+ /**
159
+ * Query memories by tenant and agent
160
+ */
161
+ async queryMemories(tenantId, agentId, limit = 100) {
162
+ const startTime = Date.now();
163
+ this.debug.logMemory('query_start', agentId, tenantId, {
164
+ limit,
165
+ hasAgentFilter: !!agentId,
166
+ });
167
+ try {
168
+ let query = this.client
169
+ .from('agent_memories')
170
+ .select('*')
171
+ .eq('tenant_id', tenantId)
172
+ .order('created_at', { ascending: false })
173
+ .limit(limit);
174
+ if (agentId) {
175
+ query = query.eq('agent_id', agentId);
176
+ }
177
+ const { data, error } = await query;
178
+ const duration = Date.now() - startTime;
179
+ if (error) {
180
+ this.debug.logMemory('query_error', agentId, tenantId, {
181
+ error: error.message,
182
+ }, duration);
183
+ throw new Error(`Failed to query memories: ${error.message}`);
184
+ }
185
+ this.debug.logMemory('query_complete', agentId, tenantId, {
186
+ count: data?.length || 0,
187
+ }, duration);
188
+ return data;
189
+ }
190
+ catch (error) {
191
+ const duration = Date.now() - startTime;
192
+ this.debug.logMemory('query_failed', agentId, tenantId, {}, duration);
193
+ throw error;
194
+ }
195
+ }
196
+ /**
197
+ * Semantic search using pgvector
198
+ */
199
+ async semanticSearch(embedding, tenantId, limit = 10) {
200
+ const startTime = Date.now();
201
+ this.debug.logMemory('semantic_search_start', undefined, tenantId, {
202
+ embedding_dims: embedding.length,
203
+ limit,
204
+ });
205
+ if (this.config.vectorBackend !== 'pgvector') {
206
+ this.debug.logMemory('semantic_search_disabled', undefined, tenantId, {
207
+ backend: this.config.vectorBackend,
208
+ });
209
+ throw new Error('pgvector backend not enabled');
210
+ }
211
+ try {
212
+ const { data, error } = await this.client.rpc('search_memories', {
213
+ query_embedding: embedding,
214
+ query_tenant_id: tenantId,
215
+ match_count: limit,
216
+ });
217
+ const duration = Date.now() - startTime;
218
+ if (error) {
219
+ this.debug.logMemory('semantic_search_error', undefined, tenantId, {
220
+ error: error.message,
221
+ }, duration);
222
+ throw new Error(`Semantic search failed: ${error.message}`);
223
+ }
224
+ this.debug.logMemory('semantic_search_complete', undefined, tenantId, {
225
+ results: data?.length || 0,
226
+ }, duration);
227
+ return data;
228
+ }
229
+ catch (error) {
230
+ const duration = Date.now() - startTime;
231
+ this.debug.logMemory('semantic_search_failed', undefined, tenantId, {}, duration);
232
+ throw error;
233
+ }
234
+ }
235
+ /**
236
+ * Register agent session
237
+ */
238
+ async registerSession(sessionId, tenantId, agentId, metadata) {
239
+ const startTime = Date.now();
240
+ this.debug.logDatabase('register_session_start', {
241
+ sessionId,
242
+ tenantId,
243
+ agentId,
244
+ });
245
+ try {
246
+ const { error } = await this.client
247
+ .from('agent_sessions')
248
+ .insert({
249
+ session_id: sessionId,
250
+ tenant_id: tenantId,
251
+ agent_id: agentId,
252
+ metadata,
253
+ started_at: new Date().toISOString(),
254
+ status: 'active',
255
+ });
256
+ const duration = Date.now() - startTime;
257
+ if (error) {
258
+ this.debug.logDatabase('register_session_error', {
259
+ sessionId,
260
+ error: error.message,
261
+ }, duration, error);
262
+ throw new Error(`Failed to register session: ${error.message}`);
263
+ }
264
+ this.debug.logDatabase('register_session_complete', {
265
+ sessionId,
266
+ }, duration);
267
+ }
268
+ catch (error) {
269
+ const duration = Date.now() - startTime;
270
+ this.debug.logDatabase('register_session_failed', { sessionId }, duration);
271
+ throw error;
272
+ }
273
+ }
274
+ /**
275
+ * Update session status
276
+ */
277
+ async updateSessionStatus(sessionId, status) {
278
+ const startTime = Date.now();
279
+ this.debug.logDatabase('update_session_start', {
280
+ sessionId,
281
+ status,
282
+ });
283
+ try {
284
+ const updates = { status };
285
+ if (status !== 'active') {
286
+ updates.ended_at = new Date().toISOString();
287
+ }
288
+ const { error } = await this.client
289
+ .from('agent_sessions')
290
+ .update(updates)
291
+ .eq('session_id', sessionId);
292
+ const duration = Date.now() - startTime;
293
+ if (error) {
294
+ this.debug.logDatabase('update_session_error', {
295
+ sessionId,
296
+ error: error.message,
297
+ }, duration, error);
298
+ throw new Error(`Failed to update session: ${error.message}`);
299
+ }
300
+ this.debug.logDatabase('update_session_complete', {
301
+ sessionId,
302
+ status,
303
+ }, duration);
304
+ }
305
+ catch (error) {
306
+ const duration = Date.now() - startTime;
307
+ this.debug.logDatabase('update_session_failed', { sessionId }, duration);
308
+ throw error;
309
+ }
310
+ }
311
+ /**
312
+ * Get hub statistics
313
+ */
314
+ async getStats(tenantId) {
315
+ const startTime = Date.now();
316
+ this.debug.logDatabase('get_stats_start', { tenantId });
317
+ try {
318
+ // Total memories
319
+ let memoriesQuery = this.client
320
+ .from('agent_memories')
321
+ .select('id', { count: 'exact', head: true });
322
+ if (tenantId) {
323
+ memoriesQuery = memoriesQuery.eq('tenant_id', tenantId);
324
+ }
325
+ const { count: totalMemories } = await memoriesQuery;
326
+ // Active sessions
327
+ let sessionsQuery = this.client
328
+ .from('agent_sessions')
329
+ .select('session_id', { count: 'exact', head: true })
330
+ .eq('status', 'active');
331
+ if (tenantId) {
332
+ sessionsQuery = sessionsQuery.eq('tenant_id', tenantId);
333
+ }
334
+ const { count: activeSessions } = await sessionsQuery;
335
+ const duration = Date.now() - startTime;
336
+ const stats = {
337
+ total_memories: totalMemories || 0,
338
+ active_sessions: activeSessions || 0,
339
+ backend: 'supabase',
340
+ vector_backend: this.config.vectorBackend,
341
+ timestamp: new Date().toISOString(),
342
+ };
343
+ this.debug.logDatabase('get_stats_complete', stats, duration);
344
+ return stats;
345
+ }
346
+ catch (error) {
347
+ const duration = Date.now() - startTime;
348
+ this.debug.logDatabase('get_stats_error', {}, duration, error);
349
+ throw error;
350
+ }
351
+ }
352
+ /**
353
+ * Get debug stream for external use
354
+ */
355
+ getDebugStream() {
356
+ return this.debug;
357
+ }
358
+ /**
359
+ * Print performance metrics
360
+ */
361
+ printMetrics() {
362
+ this.debug.printMetrics();
363
+ }
364
+ /**
365
+ * Close connection
366
+ */
367
+ async close() {
368
+ const startTime = Date.now();
369
+ this.debug.logConnection('close_start');
370
+ this.debug.close();
371
+ const duration = Date.now() - startTime;
372
+ this.debug.logConnection('close_complete', {}, duration);
373
+ }
374
+ }
375
+ /**
376
+ * Create Supabase adapter from environment variables with debug support
377
+ */
378
+ export function createSupabaseAdapterDebug() {
379
+ const url = process.env.SUPABASE_URL;
380
+ const anonKey = process.env.SUPABASE_ANON_KEY;
381
+ const serviceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
382
+ if (!url || !anonKey) {
383
+ throw new Error('Missing Supabase credentials. Set SUPABASE_URL and SUPABASE_ANON_KEY');
384
+ }
385
+ const debugLevel = process.env.DEBUG_LEVEL?.toUpperCase() || 'BASIC';
386
+ return new SupabaseFederationAdapterDebug({
387
+ url,
388
+ anonKey,
389
+ serviceRoleKey,
390
+ vectorBackend: process.env.FEDERATION_VECTOR_BACKEND || 'hybrid',
391
+ syncInterval: parseInt(process.env.FEDERATION_SYNC_INTERVAL || '60000'),
392
+ debug: {
393
+ enabled: process.env.DEBUG_ENABLED !== 'false',
394
+ level: DebugLevel[debugLevel] || DebugLevel.BASIC,
395
+ output: process.env.DEBUG_OUTPUT || 'console',
396
+ format: process.env.DEBUG_FORMAT || 'human',
397
+ outputFile: process.env.DEBUG_OUTPUT_FILE,
398
+ },
399
+ });
400
+ }
@@ -0,0 +1,258 @@
1
+ /**
2
+ * Supabase Database Adapter for Federation Hub
3
+ *
4
+ * Provides PostgreSQL backend using Supabase for:
5
+ * - Hub persistence
6
+ * - Agent metadata
7
+ * - Memory storage (optional pgvector)
8
+ * - Real-time subscriptions
9
+ */
10
+ import { createClient } from '@supabase/supabase-js';
11
+ export class SupabaseFederationAdapter {
12
+ client;
13
+ config;
14
+ constructor(config) {
15
+ this.config = config;
16
+ // Use service role key for server-side operations
17
+ const key = config.serviceRoleKey || config.anonKey;
18
+ this.client = createClient(config.url, key);
19
+ }
20
+ /**
21
+ * Initialize Supabase schema for federation
22
+ */
23
+ async initialize() {
24
+ console.log('🔧 Initializing Supabase Federation Schema...');
25
+ // Check if tables exist, create if needed
26
+ await this.ensureTables();
27
+ if (this.config.vectorBackend === 'pgvector') {
28
+ await this.ensureVectorExtension();
29
+ }
30
+ console.log('✅ Supabase Federation Schema Ready');
31
+ }
32
+ /**
33
+ * Ensure required tables exist
34
+ */
35
+ async ensureTables() {
36
+ // Note: In production, use Supabase migrations
37
+ // This is a runtime check for development
38
+ const { data, error } = await this.client
39
+ .from('agent_sessions')
40
+ .select('id')
41
+ .limit(1);
42
+ if (error && error.code === 'PGRST116') {
43
+ console.log('⚠️ Tables not found. Please run Supabase migrations.');
44
+ console.log('📖 See: docs/supabase/migrations/');
45
+ }
46
+ }
47
+ /**
48
+ * Ensure pgvector extension is enabled
49
+ */
50
+ async ensureVectorExtension() {
51
+ try {
52
+ // This requires service role key with proper permissions
53
+ const { error } = await this.client.rpc('exec_sql', {
54
+ sql: 'CREATE EXTENSION IF NOT EXISTS vector;'
55
+ });
56
+ if (error) {
57
+ console.warn('⚠️ pgvector extension check failed:', error.message);
58
+ console.log('📖 Enable manually: CREATE EXTENSION vector;');
59
+ }
60
+ }
61
+ catch (err) {
62
+ console.warn('⚠️ Could not verify pgvector extension');
63
+ }
64
+ }
65
+ /**
66
+ * Store agent memory in Supabase
67
+ */
68
+ async storeMemory(memory) {
69
+ const { error } = await this.client
70
+ .from('agent_memories')
71
+ .insert({
72
+ id: memory.id,
73
+ tenant_id: memory.tenant_id,
74
+ agent_id: memory.agent_id,
75
+ session_id: memory.session_id,
76
+ content: memory.content,
77
+ embedding: memory.embedding,
78
+ metadata: memory.metadata,
79
+ created_at: memory.created_at || new Date().toISOString(),
80
+ expires_at: memory.expires_at,
81
+ });
82
+ if (error) {
83
+ throw new Error(`Failed to store memory: ${error.message}`);
84
+ }
85
+ }
86
+ /**
87
+ * Query memories by tenant and agent
88
+ */
89
+ async queryMemories(tenantId, agentId, limit = 100) {
90
+ let query = this.client
91
+ .from('agent_memories')
92
+ .select('*')
93
+ .eq('tenant_id', tenantId)
94
+ .order('created_at', { ascending: false })
95
+ .limit(limit);
96
+ if (agentId) {
97
+ query = query.eq('agent_id', agentId);
98
+ }
99
+ const { data, error } = await query;
100
+ if (error) {
101
+ throw new Error(`Failed to query memories: ${error.message}`);
102
+ }
103
+ return data;
104
+ }
105
+ /**
106
+ * Semantic search using pgvector
107
+ */
108
+ async semanticSearch(embedding, tenantId, limit = 10) {
109
+ if (this.config.vectorBackend !== 'pgvector') {
110
+ throw new Error('pgvector backend not enabled');
111
+ }
112
+ // Use pgvector cosine similarity search
113
+ const { data, error } = await this.client.rpc('search_memories', {
114
+ query_embedding: embedding,
115
+ query_tenant_id: tenantId,
116
+ match_count: limit,
117
+ });
118
+ if (error) {
119
+ throw new Error(`Semantic search failed: ${error.message}`);
120
+ }
121
+ return data;
122
+ }
123
+ /**
124
+ * Register agent session
125
+ */
126
+ async registerSession(sessionId, tenantId, agentId, metadata) {
127
+ const { error } = await this.client
128
+ .from('agent_sessions')
129
+ .insert({
130
+ session_id: sessionId,
131
+ tenant_id: tenantId,
132
+ agent_id: agentId,
133
+ metadata,
134
+ started_at: new Date().toISOString(),
135
+ status: 'active',
136
+ });
137
+ if (error) {
138
+ throw new Error(`Failed to register session: ${error.message}`);
139
+ }
140
+ }
141
+ /**
142
+ * Update session status
143
+ */
144
+ async updateSessionStatus(sessionId, status) {
145
+ const updates = { status };
146
+ if (status !== 'active') {
147
+ updates.ended_at = new Date().toISOString();
148
+ }
149
+ const { error } = await this.client
150
+ .from('agent_sessions')
151
+ .update(updates)
152
+ .eq('session_id', sessionId);
153
+ if (error) {
154
+ throw new Error(`Failed to update session: ${error.message}`);
155
+ }
156
+ }
157
+ /**
158
+ * Get active sessions for tenant
159
+ */
160
+ async getActiveSessions(tenantId) {
161
+ const { data, error } = await this.client
162
+ .from('agent_sessions')
163
+ .select('*')
164
+ .eq('tenant_id', tenantId)
165
+ .eq('status', 'active')
166
+ .order('started_at', { ascending: false });
167
+ if (error) {
168
+ throw new Error(`Failed to get sessions: ${error.message}`);
169
+ }
170
+ return data || [];
171
+ }
172
+ /**
173
+ * Subscribe to real-time memory updates
174
+ */
175
+ subscribeToMemories(tenantId, callback) {
176
+ const subscription = this.client
177
+ .channel(`memories:${tenantId}`)
178
+ .on('postgres_changes', {
179
+ event: 'INSERT',
180
+ schema: 'public',
181
+ table: 'agent_memories',
182
+ filter: `tenant_id=eq.${tenantId}`,
183
+ }, callback)
184
+ .subscribe();
185
+ // Return unsubscribe function
186
+ return () => {
187
+ subscription.unsubscribe();
188
+ };
189
+ }
190
+ /**
191
+ * Clean up expired memories
192
+ */
193
+ async cleanupExpiredMemories() {
194
+ const { data, error } = await this.client
195
+ .from('agent_memories')
196
+ .delete()
197
+ .lt('expires_at', new Date().toISOString())
198
+ .select('id');
199
+ if (error) {
200
+ throw new Error(`Cleanup failed: ${error.message}`);
201
+ }
202
+ return data?.length || 0;
203
+ }
204
+ /**
205
+ * Get hub statistics
206
+ */
207
+ async getStats(tenantId) {
208
+ // Total memories
209
+ let memoriesQuery = this.client
210
+ .from('agent_memories')
211
+ .select('id', { count: 'exact', head: true });
212
+ if (tenantId) {
213
+ memoriesQuery = memoriesQuery.eq('tenant_id', tenantId);
214
+ }
215
+ const { count: totalMemories } = await memoriesQuery;
216
+ // Active sessions
217
+ let sessionsQuery = this.client
218
+ .from('agent_sessions')
219
+ .select('session_id', { count: 'exact', head: true })
220
+ .eq('status', 'active');
221
+ if (tenantId) {
222
+ sessionsQuery = sessionsQuery.eq('tenant_id', tenantId);
223
+ }
224
+ const { count: activeSessions } = await sessionsQuery;
225
+ return {
226
+ total_memories: totalMemories || 0,
227
+ active_sessions: activeSessions || 0,
228
+ backend: 'supabase',
229
+ vector_backend: this.config.vectorBackend,
230
+ timestamp: new Date().toISOString(),
231
+ };
232
+ }
233
+ /**
234
+ * Close connection
235
+ */
236
+ async close() {
237
+ // Supabase client doesn't need explicit closing
238
+ console.log('✅ Supabase connection closed');
239
+ }
240
+ }
241
+ /**
242
+ * Create Supabase adapter from environment variables
243
+ */
244
+ export function createSupabaseAdapter() {
245
+ const url = process.env.SUPABASE_URL;
246
+ const anonKey = process.env.SUPABASE_ANON_KEY;
247
+ const serviceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
248
+ if (!url || !anonKey) {
249
+ throw new Error('Missing Supabase credentials. Set SUPABASE_URL and SUPABASE_ANON_KEY');
250
+ }
251
+ return new SupabaseFederationAdapter({
252
+ url,
253
+ anonKey,
254
+ serviceRoleKey,
255
+ vectorBackend: process.env.FEDERATION_VECTOR_BACKEND || 'hybrid',
256
+ syncInterval: parseInt(process.env.FEDERATION_SYNC_INTERVAL || '60000'),
257
+ });
258
+ }
package/dist/utils/cli.js CHANGED
@@ -44,6 +44,11 @@ export function parseArgs() {
44
44
  options.mode = 'agent-manager';
45
45
  return options;
46
46
  }
47
+ // Check for federation command
48
+ if (args[0] === 'federation') {
49
+ options.mode = 'federation';
50
+ return options;
51
+ }
47
52
  // Check for reasoningbank command
48
53
  if (args[0] === 'reasoningbank') {
49
54
  options.mode = 'reasoningbank';