flock-core 0.5.0b71__py3-none-any.whl → 0.5.0b75__py3-none-any.whl
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.
Potentially problematic release.
This version of flock-core might be problematic. Click here for more details.
- flock/agent.py +39 -1
- flock/artifacts.py +17 -10
- flock/cli.py +1 -1
- flock/dashboard/__init__.py +2 -0
- flock/dashboard/collector.py +282 -6
- flock/dashboard/events.py +6 -0
- flock/dashboard/graph_builder.py +563 -0
- flock/dashboard/launcher.py +11 -6
- flock/dashboard/models/graph.py +156 -0
- flock/dashboard/service.py +175 -14
- flock/dashboard/static_v2/assets/index-DFRnI_mt.js +111 -0
- flock/dashboard/static_v2/assets/index-fPLNdmp1.css +1 -0
- flock/dashboard/static_v2/index.html +13 -0
- flock/dashboard/websocket.py +2 -2
- flock/engines/dspy_engine.py +27 -8
- flock/frontend/README.md +6 -6
- flock/frontend/src/App.tsx +23 -31
- flock/frontend/src/__tests__/integration/graph-snapshot.test.tsx +647 -0
- flock/frontend/src/components/details/DetailWindowContainer.tsx +13 -17
- flock/frontend/src/components/details/MessageDetailWindow.tsx +439 -0
- flock/frontend/src/components/details/MessageHistoryTab.tsx +128 -53
- flock/frontend/src/components/details/RunStatusTab.tsx +79 -38
- flock/frontend/src/components/graph/AgentNode.test.tsx +3 -1
- flock/frontend/src/components/graph/AgentNode.tsx +8 -6
- flock/frontend/src/components/graph/GraphCanvas.tsx +13 -8
- flock/frontend/src/components/graph/MessageNode.test.tsx +3 -1
- flock/frontend/src/components/graph/MessageNode.tsx +16 -3
- flock/frontend/src/components/layout/DashboardLayout.tsx +12 -9
- flock/frontend/src/components/modules/HistoricalArtifactsModule.tsx +4 -14
- flock/frontend/src/components/modules/ModuleRegistry.ts +5 -3
- flock/frontend/src/hooks/useModules.ts +12 -4
- flock/frontend/src/hooks/usePersistence.ts +5 -3
- flock/frontend/src/services/api.ts +3 -19
- flock/frontend/src/services/graphService.test.ts +330 -0
- flock/frontend/src/services/graphService.ts +75 -0
- flock/frontend/src/services/websocket.ts +104 -268
- flock/frontend/src/store/filterStore.test.ts +89 -1
- flock/frontend/src/store/filterStore.ts +38 -16
- flock/frontend/src/store/graphStore.test.ts +538 -173
- flock/frontend/src/store/graphStore.ts +374 -465
- flock/frontend/src/store/moduleStore.ts +51 -33
- flock/frontend/src/store/uiStore.ts +23 -11
- flock/frontend/src/types/graph.ts +77 -44
- flock/frontend/src/utils/mockData.ts +16 -3
- flock/frontend/vite.config.ts +2 -2
- flock/orchestrator.py +24 -6
- flock/service.py +2 -2
- flock/store.py +169 -4
- flock/themes/darkmatrix.toml +2 -2
- flock/themes/deep.toml +2 -2
- flock/themes/neopolitan.toml +4 -4
- {flock_core-0.5.0b71.dist-info → flock_core-0.5.0b75.dist-info}/METADATA +1 -1
- {flock_core-0.5.0b71.dist-info → flock_core-0.5.0b75.dist-info}/RECORD +56 -53
- flock/frontend/src/__tests__/e2e/critical-scenarios.test.tsx +0 -586
- flock/frontend/src/__tests__/integration/filtering-e2e.test.tsx +0 -391
- flock/frontend/src/__tests__/integration/graph-rendering.test.tsx +0 -640
- flock/frontend/src/services/websocket.test.ts +0 -595
- flock/frontend/src/utils/transforms.test.ts +0 -860
- flock/frontend/src/utils/transforms.ts +0 -323
- {flock_core-0.5.0b71.dist-info → flock_core-0.5.0b75.dist-info}/WHEEL +0 -0
- {flock_core-0.5.0b71.dist-info → flock_core-0.5.0b75.dist-info}/entry_points.txt +0 -0
- {flock_core-0.5.0b71.dist-info → flock_core-0.5.0b75.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,860 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { Edge } from '@xyflow/react';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Phase 4: Graph Visualization & Dual Views - Edge Derivation Tests
|
|
6
|
-
*
|
|
7
|
-
* Tests for edge derivation algorithms from DATA_MODEL.md:
|
|
8
|
-
* - deriveAgentViewEdges: Creates message flow edges between agents
|
|
9
|
-
* - deriveBlackboardViewEdges: Creates transformation edges between artifacts
|
|
10
|
-
*
|
|
11
|
-
* SPECIFICATION: docs/specs/003-real-time-dashboard/DATA_MODEL.md lines 770-853
|
|
12
|
-
* REFERENCE: docs/specs/003-real-time-dashboard/PLAN.md Phase 4
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
// Type definitions matching DATA_MODEL.md specification
|
|
16
|
-
|
|
17
|
-
interface Artifact {
|
|
18
|
-
artifact_id: string;
|
|
19
|
-
artifact_type: string;
|
|
20
|
-
produced_by: string;
|
|
21
|
-
consumed_by: string[];
|
|
22
|
-
published_at: string; // ISO timestamp
|
|
23
|
-
payload: any;
|
|
24
|
-
correlation_id: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
interface Run {
|
|
28
|
-
run_id: string;
|
|
29
|
-
agent_name: string;
|
|
30
|
-
correlation_id: string; // Groups multiple agent runs together
|
|
31
|
-
status: 'active' | 'completed' | 'error';
|
|
32
|
-
consumed_artifacts: string[];
|
|
33
|
-
produced_artifacts: string[];
|
|
34
|
-
duration_ms?: number;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
interface DashboardState {
|
|
38
|
-
artifacts: Map<string, Artifact>;
|
|
39
|
-
runs: Map<string, Run>;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Edge type definitions from DATA_MODEL.md lines 805-817
|
|
43
|
-
interface AgentViewEdge extends Edge {
|
|
44
|
-
type: 'message_flow';
|
|
45
|
-
label: string; // Format: "message_type (count)"
|
|
46
|
-
data: {
|
|
47
|
-
message_type: string;
|
|
48
|
-
message_count: number;
|
|
49
|
-
artifact_ids: string[];
|
|
50
|
-
latest_timestamp: string;
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Edge type definitions from DATA_MODEL.md lines 836-847
|
|
55
|
-
interface BlackboardViewEdge extends Edge {
|
|
56
|
-
type: 'transformation';
|
|
57
|
-
label: string; // agent_name
|
|
58
|
-
data: {
|
|
59
|
-
transformer_agent: string;
|
|
60
|
-
run_id: string;
|
|
61
|
-
duration_ms?: number;
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Function interfaces (to be implemented in transforms.ts)
|
|
66
|
-
interface EdgeTransforms {
|
|
67
|
-
deriveAgentViewEdges(state: DashboardState): AgentViewEdge[];
|
|
68
|
-
deriveBlackboardViewEdges(state: DashboardState): BlackboardViewEdge[];
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
describe('Edge Derivation Algorithms', () => {
|
|
72
|
-
let transforms: EdgeTransforms;
|
|
73
|
-
|
|
74
|
-
beforeEach(() => {
|
|
75
|
-
// Mock implementation that will fail until real implementation
|
|
76
|
-
transforms = {
|
|
77
|
-
deriveAgentViewEdges: () => {
|
|
78
|
-
throw new Error('deriveAgentViewEdges not implemented');
|
|
79
|
-
},
|
|
80
|
-
deriveBlackboardViewEdges: () => {
|
|
81
|
-
throw new Error('deriveBlackboardViewEdges not implemented');
|
|
82
|
-
},
|
|
83
|
-
};
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
describe('deriveAgentViewEdges - Message Flow Edges', () => {
|
|
87
|
-
it('should create edges between agents (source → target)', () => {
|
|
88
|
-
const state: DashboardState = {
|
|
89
|
-
artifacts: new Map([
|
|
90
|
-
[
|
|
91
|
-
'artifact-1',
|
|
92
|
-
{
|
|
93
|
-
artifact_id: 'artifact-1',
|
|
94
|
-
artifact_type: 'Movie',
|
|
95
|
-
produced_by: 'movie-agent',
|
|
96
|
-
consumed_by: ['tagline-agent'],
|
|
97
|
-
published_at: '2025-10-03T10:00:00Z',
|
|
98
|
-
payload: { title: 'Inception' },
|
|
99
|
-
correlation_id: 'corr-1',
|
|
100
|
-
},
|
|
101
|
-
],
|
|
102
|
-
]),
|
|
103
|
-
runs: new Map(),
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
expect(() => {
|
|
107
|
-
transforms.deriveAgentViewEdges(state);
|
|
108
|
-
}).toThrow('deriveAgentViewEdges not implemented');
|
|
109
|
-
|
|
110
|
-
// Expected behavior after implementation:
|
|
111
|
-
// const edges = transforms.deriveAgentViewEdges(state);
|
|
112
|
-
//
|
|
113
|
-
// expect(edges).toHaveLength(1);
|
|
114
|
-
// expect(edges[0].source).toBe('movie-agent');
|
|
115
|
-
// expect(edges[0].target).toBe('tagline-agent');
|
|
116
|
-
// expect(edges[0].type).toBe('message_flow');
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('should group edges by message_type', () => {
|
|
120
|
-
const state: DashboardState = {
|
|
121
|
-
artifacts: new Map([
|
|
122
|
-
[
|
|
123
|
-
'artifact-1',
|
|
124
|
-
{
|
|
125
|
-
artifact_id: 'artifact-1',
|
|
126
|
-
artifact_type: 'Movie',
|
|
127
|
-
produced_by: 'movie-agent',
|
|
128
|
-
consumed_by: ['tagline-agent'],
|
|
129
|
-
published_at: '2025-10-03T10:00:00Z',
|
|
130
|
-
payload: {},
|
|
131
|
-
correlation_id: 'corr-1',
|
|
132
|
-
},
|
|
133
|
-
],
|
|
134
|
-
[
|
|
135
|
-
'artifact-2',
|
|
136
|
-
{
|
|
137
|
-
artifact_id: 'artifact-2',
|
|
138
|
-
artifact_type: 'Movie',
|
|
139
|
-
produced_by: 'movie-agent',
|
|
140
|
-
consumed_by: ['tagline-agent'],
|
|
141
|
-
published_at: '2025-10-03T10:01:00Z',
|
|
142
|
-
payload: {},
|
|
143
|
-
correlation_id: 'corr-1',
|
|
144
|
-
},
|
|
145
|
-
],
|
|
146
|
-
[
|
|
147
|
-
'artifact-3',
|
|
148
|
-
{
|
|
149
|
-
artifact_id: 'artifact-3',
|
|
150
|
-
artifact_type: 'Tagline',
|
|
151
|
-
produced_by: 'tagline-agent',
|
|
152
|
-
consumed_by: ['output-agent'],
|
|
153
|
-
published_at: '2025-10-03T10:02:00Z',
|
|
154
|
-
payload: {},
|
|
155
|
-
correlation_id: 'corr-1',
|
|
156
|
-
},
|
|
157
|
-
],
|
|
158
|
-
]),
|
|
159
|
-
runs: new Map(),
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
expect(() => {
|
|
163
|
-
transforms.deriveAgentViewEdges(state);
|
|
164
|
-
}).toThrow('deriveAgentViewEdges not implemented');
|
|
165
|
-
|
|
166
|
-
// Expected behavior:
|
|
167
|
-
// const edges = transforms.deriveAgentViewEdges(state);
|
|
168
|
-
//
|
|
169
|
-
// // Should have 2 edges: movie→tagline (Movie type), tagline→output (Tagline type)
|
|
170
|
-
// expect(edges).toHaveLength(2);
|
|
171
|
-
//
|
|
172
|
-
// const movieEdge = edges.find(e => e.data.message_type === 'Movie');
|
|
173
|
-
// expect(movieEdge).toBeDefined();
|
|
174
|
-
// expect(movieEdge!.source).toBe('movie-agent');
|
|
175
|
-
// expect(movieEdge!.target).toBe('tagline-agent');
|
|
176
|
-
//
|
|
177
|
-
// const taglineEdge = edges.find(e => e.data.message_type === 'Tagline');
|
|
178
|
-
// expect(taglineEdge).toBeDefined();
|
|
179
|
-
// expect(taglineEdge!.source).toBe('tagline-agent');
|
|
180
|
-
// expect(taglineEdge!.target).toBe('output-agent');
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
it('should count artifacts per edge', () => {
|
|
184
|
-
const state: DashboardState = {
|
|
185
|
-
artifacts: new Map([
|
|
186
|
-
[
|
|
187
|
-
'artifact-1',
|
|
188
|
-
{
|
|
189
|
-
artifact_id: 'artifact-1',
|
|
190
|
-
artifact_type: 'Movie',
|
|
191
|
-
produced_by: 'movie-agent',
|
|
192
|
-
consumed_by: ['tagline-agent'],
|
|
193
|
-
published_at: '2025-10-03T10:00:00Z',
|
|
194
|
-
payload: {},
|
|
195
|
-
correlation_id: 'corr-1',
|
|
196
|
-
},
|
|
197
|
-
],
|
|
198
|
-
[
|
|
199
|
-
'artifact-2',
|
|
200
|
-
{
|
|
201
|
-
artifact_id: 'artifact-2',
|
|
202
|
-
artifact_type: 'Movie',
|
|
203
|
-
produced_by: 'movie-agent',
|
|
204
|
-
consumed_by: ['tagline-agent'],
|
|
205
|
-
published_at: '2025-10-03T10:01:00Z',
|
|
206
|
-
payload: {},
|
|
207
|
-
correlation_id: 'corr-2',
|
|
208
|
-
},
|
|
209
|
-
],
|
|
210
|
-
[
|
|
211
|
-
'artifact-3',
|
|
212
|
-
{
|
|
213
|
-
artifact_id: 'artifact-3',
|
|
214
|
-
artifact_type: 'Movie',
|
|
215
|
-
produced_by: 'movie-agent',
|
|
216
|
-
consumed_by: ['tagline-agent'],
|
|
217
|
-
published_at: '2025-10-03T10:02:00Z',
|
|
218
|
-
payload: {},
|
|
219
|
-
correlation_id: 'corr-3',
|
|
220
|
-
},
|
|
221
|
-
],
|
|
222
|
-
]),
|
|
223
|
-
runs: new Map(),
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
expect(() => {
|
|
227
|
-
transforms.deriveAgentViewEdges(state);
|
|
228
|
-
}).toThrow('deriveAgentViewEdges not implemented');
|
|
229
|
-
|
|
230
|
-
// Expected behavior:
|
|
231
|
-
// const edges = transforms.deriveAgentViewEdges(state);
|
|
232
|
-
//
|
|
233
|
-
// expect(edges).toHaveLength(1);
|
|
234
|
-
// expect(edges[0].data.message_count).toBe(3);
|
|
235
|
-
// expect(edges[0].data.artifact_ids).toHaveLength(3);
|
|
236
|
-
// expect(edges[0].data.artifact_ids).toContain('artifact-1');
|
|
237
|
-
// expect(edges[0].data.artifact_ids).toContain('artifact-2');
|
|
238
|
-
// expect(edges[0].data.artifact_ids).toContain('artifact-3');
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
it('should format edge label as "Type (N)"', () => {
|
|
242
|
-
const state: DashboardState = {
|
|
243
|
-
artifacts: new Map([
|
|
244
|
-
[
|
|
245
|
-
'artifact-1',
|
|
246
|
-
{
|
|
247
|
-
artifact_id: 'artifact-1',
|
|
248
|
-
artifact_type: 'Movie',
|
|
249
|
-
produced_by: 'movie-agent',
|
|
250
|
-
consumed_by: ['tagline-agent'],
|
|
251
|
-
published_at: '2025-10-03T10:00:00Z',
|
|
252
|
-
payload: {},
|
|
253
|
-
correlation_id: 'corr-1',
|
|
254
|
-
},
|
|
255
|
-
],
|
|
256
|
-
[
|
|
257
|
-
'artifact-2',
|
|
258
|
-
{
|
|
259
|
-
artifact_id: 'artifact-2',
|
|
260
|
-
artifact_type: 'Movie',
|
|
261
|
-
produced_by: 'movie-agent',
|
|
262
|
-
consumed_by: ['tagline-agent'],
|
|
263
|
-
published_at: '2025-10-03T10:01:00Z',
|
|
264
|
-
payload: {},
|
|
265
|
-
correlation_id: 'corr-2',
|
|
266
|
-
},
|
|
267
|
-
],
|
|
268
|
-
]),
|
|
269
|
-
runs: new Map(),
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
expect(() => {
|
|
273
|
-
transforms.deriveAgentViewEdges(state);
|
|
274
|
-
}).toThrow('deriveAgentViewEdges not implemented');
|
|
275
|
-
|
|
276
|
-
// Expected behavior:
|
|
277
|
-
// const edges = transforms.deriveAgentViewEdges(state);
|
|
278
|
-
//
|
|
279
|
-
// expect(edges).toHaveLength(1);
|
|
280
|
-
// expect(edges[0].label).toBe('Movie (2)');
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
it('should track latest_timestamp for each edge', () => {
|
|
284
|
-
const state: DashboardState = {
|
|
285
|
-
artifacts: new Map([
|
|
286
|
-
[
|
|
287
|
-
'artifact-1',
|
|
288
|
-
{
|
|
289
|
-
artifact_id: 'artifact-1',
|
|
290
|
-
artifact_type: 'Movie',
|
|
291
|
-
produced_by: 'movie-agent',
|
|
292
|
-
consumed_by: ['tagline-agent'],
|
|
293
|
-
published_at: '2025-10-03T10:00:00Z',
|
|
294
|
-
payload: {},
|
|
295
|
-
correlation_id: 'corr-1',
|
|
296
|
-
},
|
|
297
|
-
],
|
|
298
|
-
[
|
|
299
|
-
'artifact-2',
|
|
300
|
-
{
|
|
301
|
-
artifact_id: 'artifact-2',
|
|
302
|
-
artifact_type: 'Movie',
|
|
303
|
-
produced_by: 'movie-agent',
|
|
304
|
-
consumed_by: ['tagline-agent'],
|
|
305
|
-
published_at: '2025-10-03T10:05:00Z', // Latest
|
|
306
|
-
payload: {},
|
|
307
|
-
correlation_id: 'corr-2',
|
|
308
|
-
},
|
|
309
|
-
],
|
|
310
|
-
[
|
|
311
|
-
'artifact-3',
|
|
312
|
-
{
|
|
313
|
-
artifact_id: 'artifact-3',
|
|
314
|
-
artifact_type: 'Movie',
|
|
315
|
-
produced_by: 'movie-agent',
|
|
316
|
-
consumed_by: ['tagline-agent'],
|
|
317
|
-
published_at: '2025-10-03T10:02:00Z',
|
|
318
|
-
payload: {},
|
|
319
|
-
correlation_id: 'corr-3',
|
|
320
|
-
},
|
|
321
|
-
],
|
|
322
|
-
]),
|
|
323
|
-
runs: new Map(),
|
|
324
|
-
};
|
|
325
|
-
|
|
326
|
-
expect(() => {
|
|
327
|
-
transforms.deriveAgentViewEdges(state);
|
|
328
|
-
}).toThrow('deriveAgentViewEdges not implemented');
|
|
329
|
-
|
|
330
|
-
// Expected behavior:
|
|
331
|
-
// const edges = transforms.deriveAgentViewEdges(state);
|
|
332
|
-
//
|
|
333
|
-
// expect(edges).toHaveLength(1);
|
|
334
|
-
// expect(edges[0].data.latest_timestamp).toBe('2025-10-03T10:05:00Z');
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
it('should create unique edge IDs using edgeKey format', () => {
|
|
338
|
-
const state: DashboardState = {
|
|
339
|
-
artifacts: new Map([
|
|
340
|
-
[
|
|
341
|
-
'artifact-1',
|
|
342
|
-
{
|
|
343
|
-
artifact_id: 'artifact-1',
|
|
344
|
-
artifact_type: 'Movie',
|
|
345
|
-
produced_by: 'movie-agent',
|
|
346
|
-
consumed_by: ['tagline-agent'],
|
|
347
|
-
published_at: '2025-10-03T10:00:00Z',
|
|
348
|
-
payload: {},
|
|
349
|
-
correlation_id: 'corr-1',
|
|
350
|
-
},
|
|
351
|
-
],
|
|
352
|
-
]),
|
|
353
|
-
runs: new Map(),
|
|
354
|
-
};
|
|
355
|
-
|
|
356
|
-
expect(() => {
|
|
357
|
-
transforms.deriveAgentViewEdges(state);
|
|
358
|
-
}).toThrow('deriveAgentViewEdges not implemented');
|
|
359
|
-
|
|
360
|
-
// Expected behavior (from DATA_MODEL.md line 782):
|
|
361
|
-
// const edges = transforms.deriveAgentViewEdges(state);
|
|
362
|
-
//
|
|
363
|
-
// expect(edges).toHaveLength(1);
|
|
364
|
-
// // Edge ID format: `${source}_${target}_${message_type}`
|
|
365
|
-
// expect(edges[0].id).toBe('movie-agent_tagline-agent_Movie');
|
|
366
|
-
});
|
|
367
|
-
|
|
368
|
-
it('should handle multiple consumers (fan-out)', () => {
|
|
369
|
-
const state: DashboardState = {
|
|
370
|
-
artifacts: new Map([
|
|
371
|
-
[
|
|
372
|
-
'artifact-1',
|
|
373
|
-
{
|
|
374
|
-
artifact_id: 'artifact-1',
|
|
375
|
-
artifact_type: 'Movie',
|
|
376
|
-
produced_by: 'movie-agent',
|
|
377
|
-
consumed_by: ['tagline-agent', 'summary-agent', 'rating-agent'],
|
|
378
|
-
published_at: '2025-10-03T10:00:00Z',
|
|
379
|
-
payload: {},
|
|
380
|
-
correlation_id: 'corr-1',
|
|
381
|
-
},
|
|
382
|
-
],
|
|
383
|
-
]),
|
|
384
|
-
runs: new Map(),
|
|
385
|
-
};
|
|
386
|
-
|
|
387
|
-
expect(() => {
|
|
388
|
-
transforms.deriveAgentViewEdges(state);
|
|
389
|
-
}).toThrow('deriveAgentViewEdges not implemented');
|
|
390
|
-
|
|
391
|
-
// Expected behavior:
|
|
392
|
-
// const edges = transforms.deriveAgentViewEdges(state);
|
|
393
|
-
//
|
|
394
|
-
// // Should create 3 edges: movie→tagline, movie→summary, movie→rating
|
|
395
|
-
// expect(edges).toHaveLength(3);
|
|
396
|
-
//
|
|
397
|
-
// const targets = edges.map(e => e.target).sort();
|
|
398
|
-
// expect(targets).toEqual(['rating-agent', 'summary-agent', 'tagline-agent']);
|
|
399
|
-
//
|
|
400
|
-
// // All should have the same source
|
|
401
|
-
// edges.forEach(edge => {
|
|
402
|
-
// expect(edge.source).toBe('movie-agent');
|
|
403
|
-
// });
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
it('should handle empty consumed_by array (no edges)', () => {
|
|
407
|
-
const state: DashboardState = {
|
|
408
|
-
artifacts: new Map([
|
|
409
|
-
[
|
|
410
|
-
'artifact-1',
|
|
411
|
-
{
|
|
412
|
-
artifact_id: 'artifact-1',
|
|
413
|
-
artifact_type: 'Movie',
|
|
414
|
-
produced_by: 'movie-agent',
|
|
415
|
-
consumed_by: [], // No consumers
|
|
416
|
-
published_at: '2025-10-03T10:00:00Z',
|
|
417
|
-
payload: {},
|
|
418
|
-
correlation_id: 'corr-1',
|
|
419
|
-
},
|
|
420
|
-
],
|
|
421
|
-
]),
|
|
422
|
-
runs: new Map(),
|
|
423
|
-
};
|
|
424
|
-
|
|
425
|
-
expect(() => {
|
|
426
|
-
transforms.deriveAgentViewEdges(state);
|
|
427
|
-
}).toThrow('deriveAgentViewEdges not implemented');
|
|
428
|
-
|
|
429
|
-
// Expected behavior:
|
|
430
|
-
// const edges = transforms.deriveAgentViewEdges(state);
|
|
431
|
-
//
|
|
432
|
-
// // No edges should be created
|
|
433
|
-
// expect(edges).toHaveLength(0);
|
|
434
|
-
});
|
|
435
|
-
|
|
436
|
-
it('should return empty array for empty state', () => {
|
|
437
|
-
const state: DashboardState = {
|
|
438
|
-
artifacts: new Map(),
|
|
439
|
-
runs: new Map(),
|
|
440
|
-
};
|
|
441
|
-
|
|
442
|
-
expect(() => {
|
|
443
|
-
transforms.deriveAgentViewEdges(state);
|
|
444
|
-
}).toThrow('deriveAgentViewEdges not implemented');
|
|
445
|
-
|
|
446
|
-
// Expected behavior:
|
|
447
|
-
// const edges = transforms.deriveAgentViewEdges(state);
|
|
448
|
-
// expect(edges).toHaveLength(0);
|
|
449
|
-
// expect(edges).toEqual([]);
|
|
450
|
-
});
|
|
451
|
-
});
|
|
452
|
-
|
|
453
|
-
describe('deriveBlackboardViewEdges - Transformation Edges', () => {
|
|
454
|
-
it('should create edges between artifacts (consumed → produced)', () => {
|
|
455
|
-
const state: DashboardState = {
|
|
456
|
-
artifacts: new Map([
|
|
457
|
-
['artifact-1', { artifact_id: 'artifact-1' } as Artifact],
|
|
458
|
-
['artifact-2', { artifact_id: 'artifact-2' } as Artifact],
|
|
459
|
-
]),
|
|
460
|
-
runs: new Map([
|
|
461
|
-
[
|
|
462
|
-
'run-1',
|
|
463
|
-
{
|
|
464
|
-
run_id: 'run-1',
|
|
465
|
-
correlation_id: 'test-correlation',
|
|
466
|
-
agent_name: 'tagline-agent',
|
|
467
|
-
status: 'completed',
|
|
468
|
-
consumed_artifacts: ['artifact-1'],
|
|
469
|
-
produced_artifacts: ['artifact-2'],
|
|
470
|
-
duration_ms: 1500,
|
|
471
|
-
},
|
|
472
|
-
],
|
|
473
|
-
]),
|
|
474
|
-
};
|
|
475
|
-
|
|
476
|
-
expect(() => {
|
|
477
|
-
transforms.deriveBlackboardViewEdges(state);
|
|
478
|
-
}).toThrow('deriveBlackboardViewEdges not implemented');
|
|
479
|
-
|
|
480
|
-
// Expected behavior:
|
|
481
|
-
// const edges = transforms.deriveBlackboardViewEdges(state);
|
|
482
|
-
//
|
|
483
|
-
// expect(edges).toHaveLength(1);
|
|
484
|
-
// expect(edges[0].source).toBe('artifact-1');
|
|
485
|
-
// expect(edges[0].target).toBe('artifact-2');
|
|
486
|
-
// expect(edges[0].type).toBe('transformation');
|
|
487
|
-
});
|
|
488
|
-
|
|
489
|
-
it('should create one edge per consumed × produced pair', () => {
|
|
490
|
-
const state: DashboardState = {
|
|
491
|
-
artifacts: new Map([
|
|
492
|
-
['artifact-1', { artifact_id: 'artifact-1' } as Artifact],
|
|
493
|
-
['artifact-2', { artifact_id: 'artifact-2' } as Artifact],
|
|
494
|
-
['artifact-3', { artifact_id: 'artifact-3' } as Artifact],
|
|
495
|
-
]),
|
|
496
|
-
runs: new Map([
|
|
497
|
-
[
|
|
498
|
-
'run-1',
|
|
499
|
-
{
|
|
500
|
-
run_id: 'run-1',
|
|
501
|
-
correlation_id: 'test-correlation',
|
|
502
|
-
agent_name: 'multi-agent',
|
|
503
|
-
status: 'completed',
|
|
504
|
-
consumed_artifacts: ['artifact-1', 'artifact-2'],
|
|
505
|
-
produced_artifacts: ['artifact-3'],
|
|
506
|
-
duration_ms: 2000,
|
|
507
|
-
},
|
|
508
|
-
],
|
|
509
|
-
]),
|
|
510
|
-
};
|
|
511
|
-
|
|
512
|
-
expect(() => {
|
|
513
|
-
transforms.deriveBlackboardViewEdges(state);
|
|
514
|
-
}).toThrow('deriveBlackboardViewEdges not implemented');
|
|
515
|
-
|
|
516
|
-
// Expected behavior:
|
|
517
|
-
// const edges = transforms.deriveBlackboardViewEdges(state);
|
|
518
|
-
//
|
|
519
|
-
// // Should create 2 edges: artifact-1→artifact-3, artifact-2→artifact-3
|
|
520
|
-
// expect(edges).toHaveLength(2);
|
|
521
|
-
//
|
|
522
|
-
// const edge1 = edges.find(e => e.source === 'artifact-1');
|
|
523
|
-
// expect(edge1).toBeDefined();
|
|
524
|
-
// expect(edge1!.target).toBe('artifact-3');
|
|
525
|
-
//
|
|
526
|
-
// const edge2 = edges.find(e => e.source === 'artifact-2');
|
|
527
|
-
// expect(edge2).toBeDefined();
|
|
528
|
-
// expect(edge2!.target).toBe('artifact-3');
|
|
529
|
-
});
|
|
530
|
-
|
|
531
|
-
it('should label edges with agent_name', () => {
|
|
532
|
-
const state: DashboardState = {
|
|
533
|
-
artifacts: new Map([
|
|
534
|
-
['artifact-1', { artifact_id: 'artifact-1' } as Artifact],
|
|
535
|
-
['artifact-2', { artifact_id: 'artifact-2' } as Artifact],
|
|
536
|
-
]),
|
|
537
|
-
runs: new Map([
|
|
538
|
-
[
|
|
539
|
-
'run-1',
|
|
540
|
-
{
|
|
541
|
-
run_id: 'run-1',
|
|
542
|
-
correlation_id: 'test-correlation',
|
|
543
|
-
agent_name: 'tagline-agent',
|
|
544
|
-
status: 'completed',
|
|
545
|
-
consumed_artifacts: ['artifact-1'],
|
|
546
|
-
produced_artifacts: ['artifact-2'],
|
|
547
|
-
duration_ms: 1500,
|
|
548
|
-
},
|
|
549
|
-
],
|
|
550
|
-
]),
|
|
551
|
-
};
|
|
552
|
-
|
|
553
|
-
expect(() => {
|
|
554
|
-
transforms.deriveBlackboardViewEdges(state);
|
|
555
|
-
}).toThrow('deriveBlackboardViewEdges not implemented');
|
|
556
|
-
|
|
557
|
-
// Expected behavior (from DATA_MODEL.md line 841):
|
|
558
|
-
// const edges = transforms.deriveBlackboardViewEdges(state);
|
|
559
|
-
//
|
|
560
|
-
// expect(edges).toHaveLength(1);
|
|
561
|
-
// expect(edges[0].label).toBe('tagline-agent');
|
|
562
|
-
});
|
|
563
|
-
|
|
564
|
-
it('should include edge data with run metadata', () => {
|
|
565
|
-
const state: DashboardState = {
|
|
566
|
-
artifacts: new Map([
|
|
567
|
-
['artifact-1', { artifact_id: 'artifact-1' } as Artifact],
|
|
568
|
-
['artifact-2', { artifact_id: 'artifact-2' } as Artifact],
|
|
569
|
-
]),
|
|
570
|
-
runs: new Map([
|
|
571
|
-
[
|
|
572
|
-
'run-1',
|
|
573
|
-
{
|
|
574
|
-
run_id: 'run-1',
|
|
575
|
-
correlation_id: 'test-correlation',
|
|
576
|
-
agent_name: 'tagline-agent',
|
|
577
|
-
status: 'completed',
|
|
578
|
-
consumed_artifacts: ['artifact-1'],
|
|
579
|
-
produced_artifacts: ['artifact-2'],
|
|
580
|
-
duration_ms: 1500,
|
|
581
|
-
},
|
|
582
|
-
],
|
|
583
|
-
]),
|
|
584
|
-
};
|
|
585
|
-
|
|
586
|
-
expect(() => {
|
|
587
|
-
transforms.deriveBlackboardViewEdges(state);
|
|
588
|
-
}).toThrow('deriveBlackboardViewEdges not implemented');
|
|
589
|
-
|
|
590
|
-
// Expected behavior (from DATA_MODEL.md lines 842-846):
|
|
591
|
-
// const edges = transforms.deriveBlackboardViewEdges(state);
|
|
592
|
-
//
|
|
593
|
-
// expect(edges).toHaveLength(1);
|
|
594
|
-
// expect(edges[0].data).toEqual({
|
|
595
|
-
// transformer_agent: 'tagline-agent',
|
|
596
|
-
// run_id: 'run-1',
|
|
597
|
-
// correlation_id: 'test-correlation',
|
|
598
|
-
// duration_ms: 1500,
|
|
599
|
-
// });
|
|
600
|
-
});
|
|
601
|
-
|
|
602
|
-
it('should skip active runs (status === "active")', () => {
|
|
603
|
-
const state: DashboardState = {
|
|
604
|
-
artifacts: new Map([
|
|
605
|
-
['artifact-1', { artifact_id: 'artifact-1' } as Artifact],
|
|
606
|
-
['artifact-2', { artifact_id: 'artifact-2' } as Artifact],
|
|
607
|
-
]),
|
|
608
|
-
runs: new Map([
|
|
609
|
-
[
|
|
610
|
-
'run-1',
|
|
611
|
-
{
|
|
612
|
-
run_id: 'run-1',
|
|
613
|
-
correlation_id: 'test-correlation',
|
|
614
|
-
agent_name: 'active-agent',
|
|
615
|
-
status: 'active', // Still running
|
|
616
|
-
consumed_artifacts: ['artifact-1'],
|
|
617
|
-
produced_artifacts: ['artifact-2'],
|
|
618
|
-
},
|
|
619
|
-
],
|
|
620
|
-
[
|
|
621
|
-
'run-2',
|
|
622
|
-
{
|
|
623
|
-
run_id: 'run-2',
|
|
624
|
-
correlation_id: 'test-correlation',
|
|
625
|
-
agent_name: 'completed-agent',
|
|
626
|
-
status: 'completed',
|
|
627
|
-
consumed_artifacts: ['artifact-1'],
|
|
628
|
-
produced_artifacts: ['artifact-2'],
|
|
629
|
-
duration_ms: 1000,
|
|
630
|
-
},
|
|
631
|
-
],
|
|
632
|
-
]),
|
|
633
|
-
};
|
|
634
|
-
|
|
635
|
-
expect(() => {
|
|
636
|
-
transforms.deriveBlackboardViewEdges(state);
|
|
637
|
-
}).toThrow('deriveBlackboardViewEdges not implemented');
|
|
638
|
-
|
|
639
|
-
// Expected behavior (from DATA_MODEL.md line 831):
|
|
640
|
-
// const edges = transforms.deriveBlackboardViewEdges(state);
|
|
641
|
-
//
|
|
642
|
-
// // Only run-2 should create an edge (run-1 is active)
|
|
643
|
-
// expect(edges).toHaveLength(1);
|
|
644
|
-
// expect(edges[0].data.run_id).toBe('run-2');
|
|
645
|
-
});
|
|
646
|
-
|
|
647
|
-
it('should generate unique edge IDs', () => {
|
|
648
|
-
const state: DashboardState = {
|
|
649
|
-
artifacts: new Map([
|
|
650
|
-
['artifact-1', { artifact_id: 'artifact-1' } as Artifact],
|
|
651
|
-
['artifact-2', { artifact_id: 'artifact-2' } as Artifact],
|
|
652
|
-
]),
|
|
653
|
-
runs: new Map([
|
|
654
|
-
[
|
|
655
|
-
'run-1',
|
|
656
|
-
{
|
|
657
|
-
run_id: 'run-1',
|
|
658
|
-
correlation_id: 'test-correlation',
|
|
659
|
-
agent_name: 'agent-1',
|
|
660
|
-
status: 'completed',
|
|
661
|
-
consumed_artifacts: ['artifact-1'],
|
|
662
|
-
produced_artifacts: ['artifact-2'],
|
|
663
|
-
duration_ms: 1000,
|
|
664
|
-
},
|
|
665
|
-
],
|
|
666
|
-
]),
|
|
667
|
-
};
|
|
668
|
-
|
|
669
|
-
expect(() => {
|
|
670
|
-
transforms.deriveBlackboardViewEdges(state);
|
|
671
|
-
}).toThrow('deriveBlackboardViewEdges not implemented');
|
|
672
|
-
|
|
673
|
-
// Expected behavior (from DATA_MODEL.md line 837):
|
|
674
|
-
// const edges = transforms.deriveBlackboardViewEdges(state);
|
|
675
|
-
//
|
|
676
|
-
// expect(edges).toHaveLength(1);
|
|
677
|
-
// // Edge ID format: `${consumed_id}_${produced_id}`
|
|
678
|
-
// expect(edges[0].id).toBe('artifact-1_artifact-2');
|
|
679
|
-
});
|
|
680
|
-
|
|
681
|
-
it('should handle runs with no consumed artifacts', () => {
|
|
682
|
-
const state: DashboardState = {
|
|
683
|
-
artifacts: new Map([
|
|
684
|
-
['artifact-1', { artifact_id: 'artifact-1' } as Artifact],
|
|
685
|
-
]),
|
|
686
|
-
runs: new Map([
|
|
687
|
-
[
|
|
688
|
-
'run-1',
|
|
689
|
-
{
|
|
690
|
-
run_id: 'run-1',
|
|
691
|
-
correlation_id: 'test-correlation',
|
|
692
|
-
agent_name: 'source-agent',
|
|
693
|
-
status: 'completed',
|
|
694
|
-
consumed_artifacts: [], // No inputs
|
|
695
|
-
produced_artifacts: ['artifact-1'],
|
|
696
|
-
duration_ms: 500,
|
|
697
|
-
},
|
|
698
|
-
],
|
|
699
|
-
]),
|
|
700
|
-
};
|
|
701
|
-
|
|
702
|
-
expect(() => {
|
|
703
|
-
transforms.deriveBlackboardViewEdges(state);
|
|
704
|
-
}).toThrow('deriveBlackboardViewEdges not implemented');
|
|
705
|
-
|
|
706
|
-
// Expected behavior:
|
|
707
|
-
// const edges = transforms.deriveBlackboardViewEdges(state);
|
|
708
|
-
//
|
|
709
|
-
// // No edges should be created (no consumed artifacts)
|
|
710
|
-
// expect(edges).toHaveLength(0);
|
|
711
|
-
});
|
|
712
|
-
|
|
713
|
-
it('should handle runs with no produced artifacts', () => {
|
|
714
|
-
const state: DashboardState = {
|
|
715
|
-
artifacts: new Map([
|
|
716
|
-
['artifact-1', { artifact_id: 'artifact-1' } as Artifact],
|
|
717
|
-
]),
|
|
718
|
-
runs: new Map([
|
|
719
|
-
[
|
|
720
|
-
'run-1',
|
|
721
|
-
{
|
|
722
|
-
run_id: 'run-1',
|
|
723
|
-
correlation_id: 'test-correlation',
|
|
724
|
-
agent_name: 'sink-agent',
|
|
725
|
-
status: 'completed',
|
|
726
|
-
consumed_artifacts: ['artifact-1'],
|
|
727
|
-
produced_artifacts: [], // No outputs
|
|
728
|
-
duration_ms: 500,
|
|
729
|
-
},
|
|
730
|
-
],
|
|
731
|
-
]),
|
|
732
|
-
};
|
|
733
|
-
|
|
734
|
-
expect(() => {
|
|
735
|
-
transforms.deriveBlackboardViewEdges(state);
|
|
736
|
-
}).toThrow('deriveBlackboardViewEdges not implemented');
|
|
737
|
-
|
|
738
|
-
// Expected behavior:
|
|
739
|
-
// const edges = transforms.deriveBlackboardViewEdges(state);
|
|
740
|
-
//
|
|
741
|
-
// // No edges should be created (no produced artifacts)
|
|
742
|
-
// expect(edges).toHaveLength(0);
|
|
743
|
-
});
|
|
744
|
-
|
|
745
|
-
it('should return empty array for empty runs', () => {
|
|
746
|
-
const state: DashboardState = {
|
|
747
|
-
artifacts: new Map(),
|
|
748
|
-
runs: new Map(),
|
|
749
|
-
};
|
|
750
|
-
|
|
751
|
-
expect(() => {
|
|
752
|
-
transforms.deriveBlackboardViewEdges(state);
|
|
753
|
-
}).toThrow('deriveBlackboardViewEdges not implemented');
|
|
754
|
-
|
|
755
|
-
// Expected behavior:
|
|
756
|
-
// const edges = transforms.deriveBlackboardViewEdges(state);
|
|
757
|
-
// expect(edges).toHaveLength(0);
|
|
758
|
-
// expect(edges).toEqual([]);
|
|
759
|
-
});
|
|
760
|
-
});
|
|
761
|
-
|
|
762
|
-
describe('Edge Deduplication', () => {
|
|
763
|
-
it('should not duplicate Agent View edges with same source, target, and type', () => {
|
|
764
|
-
const state: DashboardState = {
|
|
765
|
-
artifacts: new Map([
|
|
766
|
-
[
|
|
767
|
-
'artifact-1',
|
|
768
|
-
{
|
|
769
|
-
artifact_id: 'artifact-1',
|
|
770
|
-
artifact_type: 'Movie',
|
|
771
|
-
produced_by: 'movie-agent',
|
|
772
|
-
consumed_by: ['tagline-agent'],
|
|
773
|
-
published_at: '2025-10-03T10:00:00Z',
|
|
774
|
-
payload: {},
|
|
775
|
-
correlation_id: 'corr-1',
|
|
776
|
-
},
|
|
777
|
-
],
|
|
778
|
-
[
|
|
779
|
-
'artifact-2',
|
|
780
|
-
{
|
|
781
|
-
artifact_id: 'artifact-2',
|
|
782
|
-
artifact_type: 'Movie',
|
|
783
|
-
produced_by: 'movie-agent',
|
|
784
|
-
consumed_by: ['tagline-agent'],
|
|
785
|
-
published_at: '2025-10-03T10:01:00Z',
|
|
786
|
-
payload: {},
|
|
787
|
-
correlation_id: 'corr-2',
|
|
788
|
-
},
|
|
789
|
-
],
|
|
790
|
-
]),
|
|
791
|
-
runs: new Map(),
|
|
792
|
-
};
|
|
793
|
-
|
|
794
|
-
expect(() => {
|
|
795
|
-
transforms.deriveAgentViewEdges(state);
|
|
796
|
-
}).toThrow('deriveAgentViewEdges not implemented');
|
|
797
|
-
|
|
798
|
-
// Expected behavior:
|
|
799
|
-
// const edges = transforms.deriveAgentViewEdges(state);
|
|
800
|
-
//
|
|
801
|
-
// // Should create only 1 edge (not 2) with count of 2
|
|
802
|
-
// expect(edges).toHaveLength(1);
|
|
803
|
-
// expect(edges[0].data.message_count).toBe(2);
|
|
804
|
-
});
|
|
805
|
-
|
|
806
|
-
it('should allow multiple Blackboard View edges with same source and target from different runs', () => {
|
|
807
|
-
const state: DashboardState = {
|
|
808
|
-
artifacts: new Map([
|
|
809
|
-
['artifact-1', { artifact_id: 'artifact-1' } as Artifact],
|
|
810
|
-
['artifact-2', { artifact_id: 'artifact-2' } as Artifact],
|
|
811
|
-
]),
|
|
812
|
-
runs: new Map([
|
|
813
|
-
[
|
|
814
|
-
'run-1',
|
|
815
|
-
{
|
|
816
|
-
run_id: 'run-1',
|
|
817
|
-
correlation_id: 'test-correlation',
|
|
818
|
-
agent_name: 'agent-1',
|
|
819
|
-
status: 'completed',
|
|
820
|
-
consumed_artifacts: ['artifact-1'],
|
|
821
|
-
produced_artifacts: ['artifact-2'],
|
|
822
|
-
duration_ms: 1000,
|
|
823
|
-
},
|
|
824
|
-
],
|
|
825
|
-
[
|
|
826
|
-
'run-2',
|
|
827
|
-
{
|
|
828
|
-
run_id: 'run-2',
|
|
829
|
-
correlation_id: 'test-correlation',
|
|
830
|
-
agent_name: 'agent-2',
|
|
831
|
-
status: 'completed',
|
|
832
|
-
consumed_artifacts: ['artifact-1'],
|
|
833
|
-
produced_artifacts: ['artifact-2'],
|
|
834
|
-
duration_ms: 1500,
|
|
835
|
-
},
|
|
836
|
-
],
|
|
837
|
-
]),
|
|
838
|
-
};
|
|
839
|
-
|
|
840
|
-
expect(() => {
|
|
841
|
-
transforms.deriveBlackboardViewEdges(state);
|
|
842
|
-
}).toThrow('deriveBlackboardViewEdges not implemented');
|
|
843
|
-
|
|
844
|
-
// Expected behavior:
|
|
845
|
-
// const edges = transforms.deriveBlackboardViewEdges(state);
|
|
846
|
-
//
|
|
847
|
-
// // Should create 2 edges (same source/target but different runs)
|
|
848
|
-
// // This will cause overlapping edges, but that's expected per spec
|
|
849
|
-
// expect(edges).toHaveLength(2);
|
|
850
|
-
//
|
|
851
|
-
// const edge1 = edges.find(e => e.data.run_id === 'run-1');
|
|
852
|
-
// const edge2 = edges.find(e => e.data.run_id === 'run-2');
|
|
853
|
-
//
|
|
854
|
-
// expect(edge1).toBeDefined();
|
|
855
|
-
// expect(edge2).toBeDefined();
|
|
856
|
-
//
|
|
857
|
-
// // Note: React Flow will need to handle overlapping edges visually
|
|
858
|
-
});
|
|
859
|
-
});
|
|
860
|
-
});
|