@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.
- package/README.md +270 -0
- package/package.json +55 -0
- package/src/__tests__/agent-adapter.test.ts +271 -0
- package/src/__tests__/agentic-flow-agent.test.ts +176 -0
- package/src/__tests__/token-optimizer.test.ts +176 -0
- package/src/agent-adapter.ts +651 -0
- package/src/agentic-flow-agent.ts +802 -0
- package/src/agentic-flow-bridge.ts +803 -0
- package/src/attention-coordinator.ts +679 -0
- package/src/feature-flags.ts +485 -0
- package/src/index.ts +466 -0
- package/src/long-running-worker.ts +871 -0
- package/src/multi-model-router.ts +1079 -0
- package/src/provider-adapter.ts +1168 -0
- package/src/sdk-bridge.ts +435 -0
- package/src/sona-adapter.ts +824 -0
- package/src/specialized-worker.ts +864 -0
- package/src/swarm-adapter.ts +1112 -0
- package/src/token-optimizer.ts +306 -0
- package/src/types.ts +494 -0
- package/src/worker-base.ts +822 -0
- package/src/worker-pool.ts +933 -0
- package/tmp.json +0 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgenticFlowAgent Test Suite
|
|
3
|
+
*
|
|
4
|
+
* Tests for ADR-001 agent delegation implementation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
8
|
+
import { AgenticFlowAgent, createAgenticFlowAgent } from '../agentic-flow-agent.js';
|
|
9
|
+
|
|
10
|
+
describe('AgenticFlowAgent', () => {
|
|
11
|
+
let agent: AgenticFlowAgent;
|
|
12
|
+
|
|
13
|
+
beforeEach(async () => {
|
|
14
|
+
agent = new AgenticFlowAgent({
|
|
15
|
+
id: 'test-agent-1',
|
|
16
|
+
name: 'Test Agent',
|
|
17
|
+
type: 'coder',
|
|
18
|
+
capabilities: ['code-generation', 'refactoring'],
|
|
19
|
+
maxConcurrentTasks: 3,
|
|
20
|
+
priority: 5,
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(async () => {
|
|
25
|
+
if (agent) {
|
|
26
|
+
await agent.shutdown();
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('Initialization', () => {
|
|
31
|
+
it('should create an agent with correct configuration', () => {
|
|
32
|
+
expect(agent.id).toBe('test-agent-1');
|
|
33
|
+
expect(agent.name).toBe('Test Agent');
|
|
34
|
+
expect(agent.type).toBe('coder');
|
|
35
|
+
expect(agent.status).toBe('spawning');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should initialize successfully', async () => {
|
|
39
|
+
await agent.initialize();
|
|
40
|
+
|
|
41
|
+
expect(agent.status).toBe('idle');
|
|
42
|
+
expect(agent.metrics?.tasksCompleted).toBe(0);
|
|
43
|
+
expect(agent.metrics?.tasksFailed).toBe(0);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should be idempotent on multiple initialize calls', async () => {
|
|
47
|
+
await agent.initialize();
|
|
48
|
+
await agent.initialize();
|
|
49
|
+
await agent.initialize();
|
|
50
|
+
|
|
51
|
+
expect(agent.status).toBe('idle');
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('Task Execution', () => {
|
|
56
|
+
beforeEach(async () => {
|
|
57
|
+
await agent.initialize();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should execute a simple task', async () => {
|
|
61
|
+
const result = await agent.executeTask({
|
|
62
|
+
id: 'task-1',
|
|
63
|
+
type: 'code',
|
|
64
|
+
description: 'Generate function',
|
|
65
|
+
input: { name: 'hello' },
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
expect(result.success).toBe(true);
|
|
69
|
+
expect(result.taskId).toBe('task-1');
|
|
70
|
+
expect(result.duration).toBeGreaterThan(0);
|
|
71
|
+
expect(agent.metrics?.tasksCompleted).toBe(1);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should update status during task execution', async () => {
|
|
75
|
+
const taskPromise = agent.executeTask({
|
|
76
|
+
id: 'task-2',
|
|
77
|
+
type: 'code',
|
|
78
|
+
description: 'Test task',
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Status should be busy during execution
|
|
82
|
+
// (Note: This might be flaky due to timing)
|
|
83
|
+
|
|
84
|
+
const result = await taskPromise;
|
|
85
|
+
expect(result.success).toBe(true);
|
|
86
|
+
expect(agent.status).toBe('idle'); // Should return to idle after completion
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should track metrics correctly', async () => {
|
|
90
|
+
await agent.executeTask({
|
|
91
|
+
id: 'task-3',
|
|
92
|
+
type: 'code',
|
|
93
|
+
description: 'Task 1',
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
await agent.executeTask({
|
|
97
|
+
id: 'task-4',
|
|
98
|
+
type: 'code',
|
|
99
|
+
description: 'Task 2',
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
expect(agent.metrics?.tasksCompleted).toBe(2);
|
|
103
|
+
expect(agent.metrics?.avgTaskDuration).toBeGreaterThan(0);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
describe('Health Monitoring', () => {
|
|
108
|
+
beforeEach(async () => {
|
|
109
|
+
await agent.initialize();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should return health status', () => {
|
|
113
|
+
const health = agent.getHealth();
|
|
114
|
+
|
|
115
|
+
expect(health.status).toBe('healthy');
|
|
116
|
+
expect(health.metrics.tasksCompleted).toBe(0);
|
|
117
|
+
expect(health.metrics.uptime).toBeGreaterThan(0);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should report healthy status with low error rate', async () => {
|
|
121
|
+
await agent.executeTask({
|
|
122
|
+
id: 'task-5',
|
|
123
|
+
type: 'code',
|
|
124
|
+
description: 'Successful task',
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const health = agent.getHealth();
|
|
128
|
+
expect(health.status).toBe('healthy');
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe('Delegation', () => {
|
|
133
|
+
it('should accept delegation reference', () => {
|
|
134
|
+
const mockAgenticFlowAgent = {
|
|
135
|
+
id: 'mock-agent',
|
|
136
|
+
type: 'coder',
|
|
137
|
+
status: 'ready',
|
|
138
|
+
initialize: async () => {},
|
|
139
|
+
shutdown: async () => {},
|
|
140
|
+
execute: async (task: unknown) => ({ result: 'delegated' }),
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
agent.setAgenticFlowReference(mockAgenticFlowAgent);
|
|
144
|
+
|
|
145
|
+
expect(agent.isDelegationEnabled()).toBe(true);
|
|
146
|
+
expect(agent.getAgenticFlowReference()).toBe(mockAgenticFlowAgent);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe('Shutdown', () => {
|
|
151
|
+
it('should shutdown gracefully', async () => {
|
|
152
|
+
await agent.initialize();
|
|
153
|
+
await agent.shutdown();
|
|
154
|
+
|
|
155
|
+
expect(agent.status).toBe('terminated');
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
describe('createAgenticFlowAgent', () => {
|
|
161
|
+
it('should create and initialize an agent', async () => {
|
|
162
|
+
const agent = await createAgenticFlowAgent({
|
|
163
|
+
id: 'factory-agent-1',
|
|
164
|
+
name: 'Factory Agent',
|
|
165
|
+
type: 'tester',
|
|
166
|
+
capabilities: ['testing'],
|
|
167
|
+
maxConcurrentTasks: 1,
|
|
168
|
+
priority: 3,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
expect(agent.id).toBe('factory-agent-1');
|
|
172
|
+
expect(agent.status).toBe('idle'); // Should be initialized
|
|
173
|
+
|
|
174
|
+
await agent.shutdown();
|
|
175
|
+
});
|
|
176
|
+
});
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token Optimizer Integration Tests
|
|
3
|
+
* Validates @sparkleideas/agentic-flow Agent Booster integration
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it, expect, beforeAll } from 'vitest';
|
|
7
|
+
import { TokenOptimizer, getTokenOptimizer } from '../token-optimizer.js';
|
|
8
|
+
|
|
9
|
+
describe('TokenOptimizer', () => {
|
|
10
|
+
let optimizer: TokenOptimizer;
|
|
11
|
+
|
|
12
|
+
beforeAll(async () => {
|
|
13
|
+
optimizer = await getTokenOptimizer();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('initialization', () => {
|
|
17
|
+
it('should initialize successfully', async () => {
|
|
18
|
+
const newOptimizer = new TokenOptimizer();
|
|
19
|
+
await newOptimizer.initialize();
|
|
20
|
+
|
|
21
|
+
const stats = newOptimizer.getStats();
|
|
22
|
+
expect(stats).toBeDefined();
|
|
23
|
+
expect(typeof stats.agenticFlowAvailable).toBe('boolean');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should detect @sparkleideas/agentic-flow availability', async () => {
|
|
27
|
+
const stats = optimizer.getStats();
|
|
28
|
+
// @sparkleideas/agentic-flow is installed in v3/node_modules
|
|
29
|
+
expect(stats.agenticFlowAvailable).toBe(true);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('getCompactContext', () => {
|
|
34
|
+
it('should return context structure', async () => {
|
|
35
|
+
const ctx = await optimizer.getCompactContext('authentication patterns');
|
|
36
|
+
|
|
37
|
+
expect(ctx).toHaveProperty('query');
|
|
38
|
+
expect(ctx).toHaveProperty('memories');
|
|
39
|
+
expect(ctx).toHaveProperty('compactPrompt');
|
|
40
|
+
expect(ctx).toHaveProperty('tokensSaved');
|
|
41
|
+
expect(ctx.query).toBe('authentication patterns');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should track tokens saved', async () => {
|
|
45
|
+
const before = optimizer.getStats().totalTokensSaved;
|
|
46
|
+
await optimizer.getCompactContext('test query');
|
|
47
|
+
const after = optimizer.getStats().totalTokensSaved;
|
|
48
|
+
|
|
49
|
+
// Should increase (or stay same if no memories found)
|
|
50
|
+
expect(after).toBeGreaterThanOrEqual(before);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('optimizedEdit', () => {
|
|
55
|
+
it('should return edit optimization result', async () => {
|
|
56
|
+
const result = await optimizer.optimizedEdit(
|
|
57
|
+
'/test/file.ts',
|
|
58
|
+
'const x = 1;',
|
|
59
|
+
'const x = 2;',
|
|
60
|
+
'typescript'
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
expect(result).toHaveProperty('speedupFactor');
|
|
64
|
+
expect(result).toHaveProperty('executionMs');
|
|
65
|
+
expect(result).toHaveProperty('method');
|
|
66
|
+
expect(['agent-booster', 'traditional']).toContain(result.method);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should track edits optimized', async () => {
|
|
70
|
+
const before = optimizer.getStats().editsOptimized;
|
|
71
|
+
await optimizer.optimizedEdit('/test.ts', 'a', 'b', 'typescript');
|
|
72
|
+
const after = optimizer.getStats().editsOptimized;
|
|
73
|
+
|
|
74
|
+
expect(after).toBeGreaterThanOrEqual(before);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe('getOptimalConfig', () => {
|
|
79
|
+
it('should return anti-drift config for small teams', () => {
|
|
80
|
+
const config = optimizer.getOptimalConfig(4);
|
|
81
|
+
|
|
82
|
+
expect(config.batchSize).toBeLessThanOrEqual(5);
|
|
83
|
+
expect(config.cacheSizeMB).toBeGreaterThanOrEqual(10);
|
|
84
|
+
expect(config.topology).toBe('hierarchical');
|
|
85
|
+
expect(config.expectedSuccessRate).toBeGreaterThanOrEqual(0.9);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should recommend mesh for very small teams', () => {
|
|
89
|
+
const config = optimizer.getOptimalConfig(3);
|
|
90
|
+
// Anti-drift still prefers hierarchical
|
|
91
|
+
expect(['mesh', 'hierarchical']).toContain(config.topology);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should handle large agent counts', () => {
|
|
95
|
+
const config = optimizer.getOptimalConfig(15);
|
|
96
|
+
|
|
97
|
+
expect(config.topology).toBe('hierarchical');
|
|
98
|
+
expect(config.batchSize).toBeLessThanOrEqual(5);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('cachedLookup', () => {
|
|
103
|
+
it('should cache results', async () => {
|
|
104
|
+
let callCount = 0;
|
|
105
|
+
const generator = async () => {
|
|
106
|
+
callCount++;
|
|
107
|
+
return { data: 'test' };
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// First call - cache miss
|
|
111
|
+
await optimizer.cachedLookup('test-key-1', generator);
|
|
112
|
+
expect(callCount).toBe(1);
|
|
113
|
+
|
|
114
|
+
// Second call - cache hit
|
|
115
|
+
await optimizer.cachedLookup('test-key-1', generator);
|
|
116
|
+
expect(callCount).toBe(1); // Should not increment
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should track cache hits and misses', async () => {
|
|
120
|
+
const before = optimizer.getStats();
|
|
121
|
+
const totalBefore = before.cacheHits + before.cacheMisses;
|
|
122
|
+
|
|
123
|
+
await optimizer.cachedLookup('unique-key-' + Date.now(), async () => 'value');
|
|
124
|
+
|
|
125
|
+
const after = optimizer.getStats();
|
|
126
|
+
const totalAfter = after.cacheHits + after.cacheMisses;
|
|
127
|
+
|
|
128
|
+
expect(totalAfter).toBe(totalBefore + 1);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe('getStats', () => {
|
|
133
|
+
it('should return all statistics', () => {
|
|
134
|
+
const stats = optimizer.getStats();
|
|
135
|
+
|
|
136
|
+
expect(stats).toHaveProperty('totalTokensSaved');
|
|
137
|
+
expect(stats).toHaveProperty('editsOptimized');
|
|
138
|
+
expect(stats).toHaveProperty('cacheHits');
|
|
139
|
+
expect(stats).toHaveProperty('cacheMisses');
|
|
140
|
+
expect(stats).toHaveProperty('memoriesRetrieved');
|
|
141
|
+
expect(stats).toHaveProperty('agenticFlowAvailable');
|
|
142
|
+
expect(stats).toHaveProperty('cacheHitRate');
|
|
143
|
+
expect(stats).toHaveProperty('estimatedMonthlySavings');
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('should calculate cache hit rate', () => {
|
|
147
|
+
const stats = optimizer.getStats();
|
|
148
|
+
expect(stats.cacheHitRate).toMatch(/^\d+(\.\d+)?%$/);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should estimate monthly savings', () => {
|
|
152
|
+
const stats = optimizer.getStats();
|
|
153
|
+
expect(stats.estimatedMonthlySavings).toMatch(/^\$\d+(\.\d+)?$/);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('generateReport', () => {
|
|
158
|
+
it('should generate markdown report', () => {
|
|
159
|
+
const report = optimizer.generateReport();
|
|
160
|
+
|
|
161
|
+
expect(report).toContain('Token Optimization Report');
|
|
162
|
+
expect(report).toContain('Tokens Saved');
|
|
163
|
+
expect(report).toContain('Edits Optimized');
|
|
164
|
+
expect(report).toContain('Cache Hit Rate');
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
describe('singleton', () => {
|
|
169
|
+
it('should return same instance via getTokenOptimizer', async () => {
|
|
170
|
+
const opt1 = await getTokenOptimizer();
|
|
171
|
+
const opt2 = await getTokenOptimizer();
|
|
172
|
+
|
|
173
|
+
expect(opt1).toBe(opt2);
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
});
|