@sparkleideas/integration 3.0.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.
@@ -0,0 +1,651 @@
1
+ /**
2
+ * AgentAdapter - Bridge between Claude Flow and @sparkleideas/agentic-flow Agents
3
+ *
4
+ * Provides bidirectional conversion and delegation patterns between:
5
+ * - Claude Flow v3 DDD agent architecture
6
+ * - @sparkleideas/agentic-flow's optimized agent implementations
7
+ *
8
+ * This implements ADR-001: Adopt @sparkleideas/agentic-flow as Core Foundation
9
+ * by providing clean conversion and delegation patterns.
10
+ *
11
+ * Pattern follows existing adapters:
12
+ * - SONAAdapter: Adapts SONA learning capabilities
13
+ * - AttentionCoordinator: Adapts Flash Attention mechanisms
14
+ * - AgentAdapter: Adapts agent lifecycle and execution
15
+ *
16
+ * @module v3/integration/agent-adapter
17
+ * @version 3.0.0-alpha.1
18
+ */
19
+
20
+ import { EventEmitter } from 'events';
21
+ import {
22
+ AgenticFlowAgent,
23
+ AgentConfig,
24
+ Task,
25
+ TaskResult,
26
+ Message,
27
+ IAgent,
28
+ IAgentConfig,
29
+ AgentStatus,
30
+ AgentType,
31
+ } from './agentic-flow-agent.js';
32
+
33
+ /**
34
+ * Interface for @sparkleideas/agentic-flow Agent (external package)
35
+ * This represents the expected API from @sparkleideas/agentic-flow's Agent class
36
+ */
37
+ interface AgenticFlowAgent_External {
38
+ id: string;
39
+ type: string;
40
+ name: string;
41
+ status: string;
42
+ config: Record<string, unknown>;
43
+
44
+ initialize?(): Promise<void>;
45
+ shutdown?(): Promise<void>;
46
+ execute?(task: unknown): Promise<unknown>;
47
+ sendMessage?(to: string, message: unknown): Promise<void>;
48
+ receiveMessage?(message: unknown): Promise<void>;
49
+ getHealth?(): Promise<unknown>;
50
+ getMetrics?(): Promise<{
51
+ tasksCompleted: number;
52
+ tasksFailed: number;
53
+ avgLatency: number;
54
+ uptime: number;
55
+ }>;
56
+ getStatus?(): string;
57
+ }
58
+
59
+ /**
60
+ * Adapter configuration
61
+ */
62
+ export interface AgentAdapterConfig {
63
+ /** Enable bidirectional sync with @sparkleideas/agentic-flow */
64
+ enableSync: boolean;
65
+ /** Auto-convert agent formats */
66
+ autoConvert: boolean;
67
+ /** Fallback to local on delegation failure */
68
+ fallbackOnError: boolean;
69
+ /** Debug mode */
70
+ debug: boolean;
71
+ }
72
+
73
+ /**
74
+ * Agent conversion result
75
+ */
76
+ export interface AgentConversionResult {
77
+ /** Converted agent */
78
+ agent: AgenticFlowAgent;
79
+ /** Conversion success */
80
+ success: boolean;
81
+ /** Conversion warnings */
82
+ warnings: string[];
83
+ /** Fields that couldn't be mapped */
84
+ unmappedFields: string[];
85
+ }
86
+
87
+ /**
88
+ * AgentAdapter - Bridges Claude Flow and @sparkleideas/agentic-flow agents
89
+ *
90
+ * This adapter provides:
91
+ * 1. Format conversion between agent representations
92
+ * 2. Delegation management for optimized operations
93
+ * 3. Bidirectional synchronization of agent state
94
+ * 4. Fallback handling when @sparkleideas/agentic-flow is unavailable
95
+ *
96
+ * Usage:
97
+ * ```typescript
98
+ * const adapter = new AgentAdapter({
99
+ * enableSync: true,
100
+ * autoConvert: true,
101
+ * fallbackOnError: true,
102
+ * });
103
+ *
104
+ * await adapter.initialize();
105
+ *
106
+ * // Convert @sparkleideas/agentic-flow agent to Claude Flow agent
107
+ * const { agent, success } = adapter.fromAgenticFlow(agenticFlowAgent);
108
+ *
109
+ * // Create Claude Flow agent with @sparkleideas/agentic-flow delegation
110
+ * const delegatedAgent = await adapter.createWithDelegation({
111
+ * id: 'agent-1',
112
+ * name: 'Coder',
113
+ * type: 'coder',
114
+ * capabilities: ['code-generation'],
115
+ * maxConcurrentTasks: 3,
116
+ * priority: 5,
117
+ * });
118
+ * ```
119
+ */
120
+ export class AgentAdapter extends EventEmitter {
121
+ private config: AgentAdapterConfig;
122
+ private initialized: boolean = false;
123
+ private agentMap: Map<string, AgenticFlowAgent> = new Map();
124
+ private delegationMap: Map<string, AgenticFlowAgent_External> = new Map();
125
+
126
+ /**
127
+ * Reference to @sparkleideas/agentic-flow core for accessing Agent factory
128
+ */
129
+ private agenticFlowCore: any = null;
130
+
131
+ constructor(config: Partial<AgentAdapterConfig> = {}) {
132
+ super();
133
+
134
+ this.config = {
135
+ enableSync: config.enableSync ?? true,
136
+ autoConvert: config.autoConvert ?? true,
137
+ fallbackOnError: config.fallbackOnError ?? true,
138
+ debug: config.debug ?? false,
139
+ };
140
+ }
141
+
142
+ /**
143
+ * Initialize the adapter
144
+ */
145
+ async initialize(): Promise<void> {
146
+ if (this.initialized) {
147
+ return;
148
+ }
149
+
150
+ this.emit('initializing');
151
+
152
+ try {
153
+ // Attempt to load @sparkleideas/agentic-flow for delegation
154
+ await this.connectToAgenticFlow();
155
+
156
+ this.initialized = true;
157
+ this.emit('initialized', {
158
+ agenticFlowAvailable: this.agenticFlowCore !== null,
159
+ });
160
+ } catch (error) {
161
+ this.emit('initialization-failed', { error });
162
+ throw error;
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Shutdown the adapter
168
+ */
169
+ async shutdown(): Promise<void> {
170
+ // Shutdown all managed agents
171
+ const shutdownPromises: Promise<void>[] = [];
172
+ const agents = this.getAllAgents();
173
+
174
+ for (const agent of agents) {
175
+ shutdownPromises.push(agent.shutdown());
176
+ }
177
+
178
+ await Promise.allSettled(shutdownPromises);
179
+
180
+ this.agentMap.clear();
181
+ this.delegationMap.clear();
182
+ this.initialized = false;
183
+
184
+ this.emit('shutdown');
185
+ }
186
+
187
+ /**
188
+ * Convert @sparkleideas/agentic-flow agent to Claude Flow AgenticFlowAgent
189
+ *
190
+ * This method creates a Claude Flow agent wrapper around an existing
191
+ * @sparkleideas/agentic-flow agent instance, enabling delegation and integration.
192
+ *
193
+ * @param agenticFlowAgent - @sparkleideas/agentic-flow agent instance
194
+ * @returns Conversion result with wrapped agent
195
+ */
196
+ fromAgenticFlow(
197
+ agenticFlowAgent: AgenticFlowAgent_External
198
+ ): AgentConversionResult {
199
+ const warnings: string[] = [];
200
+ const unmappedFields: string[] = [];
201
+
202
+ try {
203
+ // Map @sparkleideas/agentic-flow config to Claude Flow config
204
+ const config: AgentConfig = {
205
+ id: agenticFlowAgent.id,
206
+ name: agenticFlowAgent.name,
207
+ type: this.mapAgentType(agenticFlowAgent.type, warnings),
208
+ capabilities: this.extractCapabilities(agenticFlowAgent.config, warnings),
209
+ maxConcurrentTasks: this.extractMaxTasks(agenticFlowAgent.config),
210
+ priority: this.extractPriority(agenticFlowAgent.config),
211
+ enableDelegation: true,
212
+ agenticFlowConfig: agenticFlowAgent.config,
213
+ };
214
+
215
+ // Create Claude Flow agent
216
+ const agent = new AgenticFlowAgent(config);
217
+
218
+ // Set delegation reference
219
+ agent.setAgenticFlowReference({
220
+ id: agenticFlowAgent.id,
221
+ type: agenticFlowAgent.type,
222
+ status: agenticFlowAgent.status,
223
+ initialize: agenticFlowAgent.initialize?.bind(agenticFlowAgent),
224
+ shutdown: agenticFlowAgent.shutdown?.bind(agenticFlowAgent),
225
+ execute: agenticFlowAgent.execute?.bind(agenticFlowAgent),
226
+ sendMessage: agenticFlowAgent.sendMessage?.bind(agenticFlowAgent),
227
+ getHealth: agenticFlowAgent.getHealth?.bind(agenticFlowAgent),
228
+ getMetrics: agenticFlowAgent.getMetrics?.bind(agenticFlowAgent),
229
+ });
230
+
231
+ // Store mapping
232
+ this.agentMap.set(agent.id, agent);
233
+ this.delegationMap.set(agent.id, agenticFlowAgent);
234
+
235
+ // Sync status if enabled
236
+ if (this.config.enableSync) {
237
+ this.syncStatus(agent, agenticFlowAgent);
238
+ }
239
+
240
+ this.emit('agent-converted', {
241
+ agentId: agent.id,
242
+ direction: 'from-agentic-flow',
243
+ warnings,
244
+ });
245
+
246
+ return {
247
+ agent,
248
+ success: true,
249
+ warnings,
250
+ unmappedFields,
251
+ };
252
+ } catch (error) {
253
+ warnings.push(`Conversion error: ${(error as Error).message}`);
254
+
255
+ // Create fallback agent if enabled
256
+ if (this.config.fallbackOnError) {
257
+ const fallbackAgent = new AgenticFlowAgent({
258
+ id: agenticFlowAgent.id,
259
+ name: agenticFlowAgent.name,
260
+ type: 'custom',
261
+ capabilities: [],
262
+ maxConcurrentTasks: 1,
263
+ priority: 0,
264
+ enableDelegation: false,
265
+ });
266
+
267
+ return {
268
+ agent: fallbackAgent,
269
+ success: false,
270
+ warnings,
271
+ unmappedFields,
272
+ };
273
+ }
274
+
275
+ throw error;
276
+ }
277
+ }
278
+
279
+ /**
280
+ * Convert Claude Flow AgenticFlowAgent to @sparkleideas/agentic-flow format
281
+ *
282
+ * This exports the agent configuration in a format compatible with
283
+ * @sparkleideas/agentic-flow's Agent constructor/factory.
284
+ *
285
+ * @param agent - Claude Flow agent instance
286
+ * @returns @sparkleideas/agentic-flow compatible configuration
287
+ */
288
+ toAgenticFlow(agent: AgenticFlowAgent): Record<string, unknown> {
289
+ return {
290
+ id: agent.id,
291
+ name: agent.name,
292
+ type: agent.type,
293
+ status: agent.status,
294
+ config: {
295
+ capabilities: agent.config.capabilities,
296
+ maxConcurrentTasks: agent.config.maxConcurrentTasks,
297
+ priority: agent.config.priority,
298
+ timeout: agent.config.timeout,
299
+ retryPolicy: agent.config.retryPolicy,
300
+ resources: agent.config.resources,
301
+ metadata: agent.config.metadata,
302
+ },
303
+ sessionId: agent.sessionId,
304
+ terminalId: agent.terminalId,
305
+ memoryBankId: agent.memoryBankId,
306
+ };
307
+ }
308
+
309
+ /**
310
+ * Create a Claude Flow agent with @sparkleideas/agentic-flow delegation
311
+ *
312
+ * This is the primary method for creating agents in v3 with
313
+ * automatic delegation to @sparkleideas/agentic-flow when available.
314
+ *
315
+ * ADR-001: Eliminates duplicate code by delegating to @sparkleideas/agentic-flow
316
+ * for core agent operations when the package is available.
317
+ *
318
+ * @param config - Agent configuration
319
+ * @returns Initialized agent with delegation enabled
320
+ */
321
+ async createWithDelegation(config: AgentConfig): Promise<AgenticFlowAgent> {
322
+ this.ensureInitialized();
323
+
324
+ const agent = new AgenticFlowAgent({
325
+ ...config,
326
+ enableDelegation: true,
327
+ });
328
+
329
+ // If @sparkleideas/agentic-flow is available, create delegation reference
330
+ if (this.agenticFlowCore && this.agenticFlowCore.createAgent) {
331
+ try {
332
+ const agenticFlowAgent = await this.agenticFlowCore.createAgent({
333
+ id: config.id,
334
+ name: config.name,
335
+ type: config.type,
336
+ config: {
337
+ capabilities: config.capabilities,
338
+ maxConcurrentTasks: config.maxConcurrentTasks,
339
+ priority: config.priority,
340
+ },
341
+ });
342
+
343
+ // Set delegation reference
344
+ agent.setAgenticFlowReference({
345
+ id: agenticFlowAgent.id,
346
+ type: agenticFlowAgent.type,
347
+ status: agenticFlowAgent.status,
348
+ initialize: agenticFlowAgent.initialize?.bind(agenticFlowAgent),
349
+ shutdown: agenticFlowAgent.shutdown?.bind(agenticFlowAgent),
350
+ execute: agenticFlowAgent.execute?.bind(agenticFlowAgent),
351
+ sendMessage: agenticFlowAgent.sendMessage?.bind(agenticFlowAgent),
352
+ getHealth: agenticFlowAgent.getHealth?.bind(agenticFlowAgent),
353
+ getMetrics: agenticFlowAgent.getMetrics?.bind(agenticFlowAgent),
354
+ });
355
+
356
+ this.delegationMap.set(agent.id, agenticFlowAgent);
357
+
358
+ this.emit('agent-created-with-delegation', {
359
+ agentId: agent.id,
360
+ delegated: true,
361
+ });
362
+ } catch (error) {
363
+ this.emit('delegation-setup-failed', {
364
+ agentId: agent.id,
365
+ error: (error as Error).message,
366
+ });
367
+
368
+ // Continue with local-only agent if fallback enabled
369
+ if (!this.config.fallbackOnError) {
370
+ throw error;
371
+ }
372
+ }
373
+ }
374
+
375
+ // Initialize the agent
376
+ await agent.initialize();
377
+
378
+ // Store in map
379
+ this.agentMap.set(agent.id, agent);
380
+
381
+ return agent;
382
+ }
383
+
384
+ /**
385
+ * Get a managed agent by ID
386
+ */
387
+ getAgent(agentId: string): AgenticFlowAgent | undefined {
388
+ return this.agentMap.get(agentId);
389
+ }
390
+
391
+ /**
392
+ * Get all managed agents
393
+ */
394
+ getAllAgents(): AgenticFlowAgent[] {
395
+ const agents: AgenticFlowAgent[] = [];
396
+ this.agentMap.forEach((agent) => {
397
+ agents.push(agent);
398
+ });
399
+ return agents;
400
+ }
401
+
402
+ /**
403
+ * Check if an agent is delegated to @sparkleideas/agentic-flow
404
+ */
405
+ isDelegated(agentId: string): boolean {
406
+ return this.delegationMap.has(agentId);
407
+ }
408
+
409
+ /**
410
+ * Get delegation reference for an agent
411
+ */
412
+ getDelegationReference(agentId: string): AgenticFlowAgent_External | undefined {
413
+ return this.delegationMap.get(agentId);
414
+ }
415
+
416
+ /**
417
+ * Remove an agent from management
418
+ */
419
+ async removeAgent(agentId: string): Promise<boolean> {
420
+ const agent = this.agentMap.get(agentId);
421
+ if (!agent) {
422
+ return false;
423
+ }
424
+
425
+ // Shutdown agent
426
+ await agent.shutdown();
427
+
428
+ // Remove from maps
429
+ this.agentMap.delete(agentId);
430
+ this.delegationMap.delete(agentId);
431
+
432
+ this.emit('agent-removed', { agentId });
433
+
434
+ return true;
435
+ }
436
+
437
+ // ===== Private Methods =====
438
+
439
+ /**
440
+ * Connect to @sparkleideas/agentic-flow package dynamically
441
+ */
442
+ private async connectToAgenticFlow(): Promise<void> {
443
+ try {
444
+ // Dynamic import to handle optional dependency
445
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
446
+ const agenticFlowModule: any = await import('@sparkleideas/agentic-flow').catch(() => null);
447
+
448
+ if (agenticFlowModule && typeof agenticFlowModule.createAgenticFlow === 'function') {
449
+ this.agenticFlowCore = await agenticFlowModule.createAgenticFlow({});
450
+
451
+ this.emit('agentic-flow-connected', {
452
+ version: this.agenticFlowCore.version,
453
+ });
454
+
455
+ this.logDebug('Connected to @sparkleideas/agentic-flow', {
456
+ version: this.agenticFlowCore.version,
457
+ });
458
+ } else {
459
+ this.agenticFlowCore = null;
460
+ this.emit('agentic-flow-unavailable', {
461
+ reason: 'package not found or incompatible',
462
+ });
463
+ this.logDebug('@sparkleideas/agentic-flow not available, using local implementations');
464
+ }
465
+ } catch (error) {
466
+ this.agenticFlowCore = null;
467
+ this.emit('agentic-flow-connection-failed', {
468
+ error: (error as Error).message,
469
+ });
470
+ this.logDebug('@sparkleideas/agentic-flow connection failed', error);
471
+ }
472
+ }
473
+
474
+ /**
475
+ * Map @sparkleideas/agentic-flow agent type to Claude Flow AgentType
476
+ */
477
+ private mapAgentType(type: string, warnings: string[]): AgentType | string {
478
+ // Known valid agent types that pass through directly
479
+ const validTypes: AgentType[] = [
480
+ 'coder',
481
+ 'reviewer',
482
+ 'tester',
483
+ 'researcher',
484
+ 'planner',
485
+ 'architect',
486
+ 'coordinator',
487
+ 'security',
488
+ 'performance',
489
+ 'custom',
490
+ ];
491
+
492
+ const lowercaseType = type.toLowerCase();
493
+
494
+ // If it's already a valid type, pass through
495
+ if (validTypes.includes(lowercaseType as AgentType)) {
496
+ return lowercaseType as AgentType;
497
+ }
498
+
499
+ // Map alternative names to valid types
500
+ const typeMap: Record<string, AgentType> = {
501
+ 'code-generator': 'coder',
502
+ 'code-reviewer': 'reviewer',
503
+ 'research': 'researcher',
504
+ 'planning': 'planner',
505
+ 'architecture': 'architect',
506
+ 'coordination': 'coordinator',
507
+ };
508
+
509
+ const mapped = typeMap[lowercaseType];
510
+ if (mapped) {
511
+ return mapped;
512
+ }
513
+
514
+ // Unknown type - generate warning and use as-is
515
+ warnings.push(`Unknown agent type '${type}', using as-is`);
516
+ return type;
517
+ }
518
+
519
+ /**
520
+ * Extract capabilities from @sparkleideas/agentic-flow config
521
+ */
522
+ private extractCapabilities(
523
+ config: Record<string, unknown>,
524
+ warnings: string[]
525
+ ): string[] {
526
+ if (Array.isArray(config.capabilities)) {
527
+ return config.capabilities as string[];
528
+ }
529
+
530
+ if (Array.isArray(config.skills)) {
531
+ warnings.push("Using 'skills' as capabilities");
532
+ return config.skills as string[];
533
+ }
534
+
535
+ return [];
536
+ }
537
+
538
+ /**
539
+ * Extract max concurrent tasks from config
540
+ */
541
+ private extractMaxTasks(config: Record<string, unknown>): number {
542
+ if (typeof config.maxConcurrentTasks === 'number') {
543
+ return config.maxConcurrentTasks;
544
+ }
545
+
546
+ if (typeof config.maxTasks === 'number') {
547
+ return config.maxTasks;
548
+ }
549
+
550
+ return 3; // Default
551
+ }
552
+
553
+ /**
554
+ * Extract priority from config
555
+ */
556
+ private extractPriority(config: Record<string, unknown>): number {
557
+ if (typeof config.priority === 'number') {
558
+ return config.priority;
559
+ }
560
+
561
+ return 5; // Default
562
+ }
563
+
564
+ /**
565
+ * Sync status between Claude Flow and @sparkleideas/agentic-flow agents
566
+ */
567
+ private syncStatus(
568
+ agent: AgenticFlowAgent,
569
+ agenticFlowAgent: AgenticFlowAgent_External
570
+ ): void {
571
+ // Map @sparkleideas/agentic-flow status to Claude Flow status
572
+ const statusMap: Record<string, AgentStatus> = {
573
+ 'initializing': 'spawning',
574
+ 'ready': 'idle',
575
+ 'active': 'active',
576
+ 'working': 'busy',
577
+ 'idle': 'idle',
578
+ 'busy': 'busy',
579
+ 'error': 'error',
580
+ 'stopped': 'terminated',
581
+ 'terminated': 'terminated',
582
+ };
583
+
584
+ const mappedStatus = statusMap[agenticFlowAgent.status.toLowerCase()];
585
+ if (mappedStatus && mappedStatus !== agent.status) {
586
+ agent.status = mappedStatus;
587
+ this.emit('status-synced', {
588
+ agentId: agent.id,
589
+ from: agenticFlowAgent.status,
590
+ to: mappedStatus,
591
+ });
592
+ }
593
+ }
594
+
595
+ /**
596
+ * Ensure adapter is initialized
597
+ */
598
+ private ensureInitialized(): void {
599
+ if (!this.initialized) {
600
+ throw new Error('AgentAdapter not initialized. Call initialize() first.');
601
+ }
602
+ }
603
+
604
+ /**
605
+ * Debug logging
606
+ */
607
+ private logDebug(message: string, data?: unknown): void {
608
+ if (this.config.debug) {
609
+ console.debug(`[AgentAdapter] ${message}`, data || '');
610
+ }
611
+ }
612
+ }
613
+
614
+ /**
615
+ * Create and initialize an AgentAdapter
616
+ */
617
+ export async function createAgentAdapter(
618
+ config?: Partial<AgentAdapterConfig>
619
+ ): Promise<AgentAdapter> {
620
+ const adapter = new AgentAdapter(config);
621
+ await adapter.initialize();
622
+ return adapter;
623
+ }
624
+
625
+ /**
626
+ * Singleton instance for simple usage
627
+ */
628
+ let defaultAdapter: AgentAdapter | null = null;
629
+
630
+ /**
631
+ * Get the default adapter instance (creates if needed)
632
+ */
633
+ export async function getDefaultAgentAdapter(
634
+ config?: Partial<AgentAdapterConfig>
635
+ ): Promise<AgentAdapter> {
636
+ if (!defaultAdapter) {
637
+ defaultAdapter = new AgentAdapter(config);
638
+ await defaultAdapter.initialize();
639
+ }
640
+ return defaultAdapter;
641
+ }
642
+
643
+ /**
644
+ * Reset the default adapter (useful for testing)
645
+ */
646
+ export async function resetDefaultAgentAdapter(): Promise<void> {
647
+ if (defaultAdapter) {
648
+ await defaultAdapter.shutdown();
649
+ defaultAdapter = null;
650
+ }
651
+ }