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.

Files changed (62) hide show
  1. flock/agent.py +39 -1
  2. flock/artifacts.py +17 -10
  3. flock/cli.py +1 -1
  4. flock/dashboard/__init__.py +2 -0
  5. flock/dashboard/collector.py +282 -6
  6. flock/dashboard/events.py +6 -0
  7. flock/dashboard/graph_builder.py +563 -0
  8. flock/dashboard/launcher.py +11 -6
  9. flock/dashboard/models/graph.py +156 -0
  10. flock/dashboard/service.py +175 -14
  11. flock/dashboard/static_v2/assets/index-DFRnI_mt.js +111 -0
  12. flock/dashboard/static_v2/assets/index-fPLNdmp1.css +1 -0
  13. flock/dashboard/static_v2/index.html +13 -0
  14. flock/dashboard/websocket.py +2 -2
  15. flock/engines/dspy_engine.py +27 -8
  16. flock/frontend/README.md +6 -6
  17. flock/frontend/src/App.tsx +23 -31
  18. flock/frontend/src/__tests__/integration/graph-snapshot.test.tsx +647 -0
  19. flock/frontend/src/components/details/DetailWindowContainer.tsx +13 -17
  20. flock/frontend/src/components/details/MessageDetailWindow.tsx +439 -0
  21. flock/frontend/src/components/details/MessageHistoryTab.tsx +128 -53
  22. flock/frontend/src/components/details/RunStatusTab.tsx +79 -38
  23. flock/frontend/src/components/graph/AgentNode.test.tsx +3 -1
  24. flock/frontend/src/components/graph/AgentNode.tsx +8 -6
  25. flock/frontend/src/components/graph/GraphCanvas.tsx +13 -8
  26. flock/frontend/src/components/graph/MessageNode.test.tsx +3 -1
  27. flock/frontend/src/components/graph/MessageNode.tsx +16 -3
  28. flock/frontend/src/components/layout/DashboardLayout.tsx +12 -9
  29. flock/frontend/src/components/modules/HistoricalArtifactsModule.tsx +4 -14
  30. flock/frontend/src/components/modules/ModuleRegistry.ts +5 -3
  31. flock/frontend/src/hooks/useModules.ts +12 -4
  32. flock/frontend/src/hooks/usePersistence.ts +5 -3
  33. flock/frontend/src/services/api.ts +3 -19
  34. flock/frontend/src/services/graphService.test.ts +330 -0
  35. flock/frontend/src/services/graphService.ts +75 -0
  36. flock/frontend/src/services/websocket.ts +104 -268
  37. flock/frontend/src/store/filterStore.test.ts +89 -1
  38. flock/frontend/src/store/filterStore.ts +38 -16
  39. flock/frontend/src/store/graphStore.test.ts +538 -173
  40. flock/frontend/src/store/graphStore.ts +374 -465
  41. flock/frontend/src/store/moduleStore.ts +51 -33
  42. flock/frontend/src/store/uiStore.ts +23 -11
  43. flock/frontend/src/types/graph.ts +77 -44
  44. flock/frontend/src/utils/mockData.ts +16 -3
  45. flock/frontend/vite.config.ts +2 -2
  46. flock/orchestrator.py +24 -6
  47. flock/service.py +2 -2
  48. flock/store.py +169 -4
  49. flock/themes/darkmatrix.toml +2 -2
  50. flock/themes/deep.toml +2 -2
  51. flock/themes/neopolitan.toml +4 -4
  52. {flock_core-0.5.0b71.dist-info → flock_core-0.5.0b75.dist-info}/METADATA +1 -1
  53. {flock_core-0.5.0b71.dist-info → flock_core-0.5.0b75.dist-info}/RECORD +56 -53
  54. flock/frontend/src/__tests__/e2e/critical-scenarios.test.tsx +0 -586
  55. flock/frontend/src/__tests__/integration/filtering-e2e.test.tsx +0 -391
  56. flock/frontend/src/__tests__/integration/graph-rendering.test.tsx +0 -640
  57. flock/frontend/src/services/websocket.test.ts +0 -595
  58. flock/frontend/src/utils/transforms.test.ts +0 -860
  59. flock/frontend/src/utils/transforms.ts +0 -323
  60. {flock_core-0.5.0b71.dist-info → flock_core-0.5.0b75.dist-info}/WHEEL +0 -0
  61. {flock_core-0.5.0b71.dist-info → flock_core-0.5.0b75.dist-info}/entry_points.txt +0 -0
  62. {flock_core-0.5.0b71.dist-info → flock_core-0.5.0b75.dist-info}/licenses/LICENSE +0 -0
@@ -1,323 +0,0 @@
1
- import { Edge } from '@xyflow/react';
2
-
3
- /**
4
- * Phase 4: Graph Visualization & Dual Views - Edge Derivation Algorithms
5
- *
6
- * Implements edge derivation logic as specified in DATA_MODEL.md:
7
- * - deriveAgentViewEdges: Creates message flow edges between agents (producer → consumer)
8
- * - deriveBlackboardViewEdges: Creates transformation edges between artifacts (consumed → produced)
9
- *
10
- * SPECIFICATION: docs/specs/003-real-time-dashboard/DATA_MODEL.md lines 770-853
11
- * REFERENCE: docs/specs/003-real-time-dashboard/PLAN.md Phase 4
12
- */
13
-
14
- // Type definitions matching DATA_MODEL.md specification
15
- export interface Artifact {
16
- artifact_id: string;
17
- artifact_type: string;
18
- produced_by: string;
19
- consumed_by: string[];
20
- published_at: string; // ISO timestamp
21
- payload: any;
22
- correlation_id: string;
23
- }
24
-
25
- export interface Run {
26
- run_id: string;
27
- agent_name: string;
28
- correlation_id: string; // Groups multiple agent runs together
29
- status: 'active' | 'completed' | 'error';
30
- consumed_artifacts: string[];
31
- produced_artifacts: string[];
32
- duration_ms?: number;
33
- started_at?: string;
34
- completed_at?: string;
35
- metrics?: {
36
- tokensUsed?: number;
37
- costUsd?: number;
38
- artifactsProduced?: number;
39
- };
40
- error_message?: string;
41
- }
42
-
43
- export interface DashboardState {
44
- artifacts: Map<string, Artifact>;
45
- runs: Map<string, Run>;
46
- consumptions: Map<string, string[]>; // Phase 11: Track actual consumption (artifact_id -> consumer_ids[])
47
- }
48
-
49
- // Edge type definitions from DATA_MODEL.md
50
- // Note: Using camelCase for TypeScript/JavaScript convention
51
- export interface AgentViewEdge extends Edge {
52
- type: 'message_flow';
53
- label: string; // Format: "messageType (count)"
54
- data: {
55
- messageType: string;
56
- messageCount: number;
57
- artifactIds: string[];
58
- latestTimestamp: string;
59
- labelOffset?: number; // Phase 11: Vertical offset in pixels to prevent label overlap
60
- };
61
- }
62
-
63
- export interface BlackboardViewEdge extends Edge {
64
- type: 'transformation';
65
- label: string; // agentName
66
- data: {
67
- transformerAgent: string;
68
- runId: string;
69
- durationMs?: number;
70
- labelOffset?: number; // Phase 11: Vertical offset in pixels to prevent label overlap
71
- };
72
- }
73
-
74
- /**
75
- * Derive Agent View edges from dashboard state
76
- *
77
- * Algorithm (DATA_MODEL.md lines 770-821):
78
- * 1. Group messages by (producer, consumer, message_type)
79
- * 2. Create one edge per unique triple
80
- * 3. Count artifacts in each group
81
- * 4. Track latest timestamp
82
- * 5. Add label offset for multiple edges between same nodes (Phase 11 bug fix)
83
- *
84
- * Edge format:
85
- * - ID: `${producer}_${consumer}_${message_type}`
86
- * - Type: 'message_flow'
87
- * - Label: "Type (N)" where N is the count
88
- * - Data: { message_type, message_count, artifact_ids[], latest_timestamp, labelOffset }
89
- *
90
- * @param state - Dashboard state with artifacts and runs
91
- * @returns Array of message flow edges
92
- */
93
- export function deriveAgentViewEdges(state: DashboardState): AgentViewEdge[] {
94
- const edgeMap = new Map<
95
- string,
96
- {
97
- source: string;
98
- target: string;
99
- message_type: string;
100
- artifact_ids: string[];
101
- latest_timestamp: string;
102
- }
103
- >();
104
-
105
- // Iterate through all artifacts
106
- state.artifacts.forEach((artifact) => {
107
- const producer = artifact.produced_by;
108
- const messageType = artifact.artifact_type;
109
-
110
- // For each consumer, create or update edge
111
- artifact.consumed_by.forEach((consumer) => {
112
- const edgeKey = `${producer}_${consumer}_${messageType}`;
113
-
114
- const existing = edgeMap.get(edgeKey);
115
-
116
- if (existing) {
117
- // Update existing edge
118
- existing.artifact_ids.push(artifact.artifact_id);
119
-
120
- // Update latest timestamp if this artifact is newer
121
- if (artifact.published_at > existing.latest_timestamp) {
122
- existing.latest_timestamp = artifact.published_at;
123
- }
124
- } else {
125
- // Create new edge entry
126
- edgeMap.set(edgeKey, {
127
- source: producer,
128
- target: consumer,
129
- message_type: messageType,
130
- artifact_ids: [artifact.artifact_id],
131
- latest_timestamp: artifact.published_at,
132
- });
133
- }
134
- });
135
- });
136
-
137
- // Phase 11 Bug Fix: Calculate label offsets for edges between same node pairs
138
- // Group edges by node pair to detect multiple edges
139
- // Use canonical pair key (sorted) so A→B and B→A are treated as same pair
140
- const nodePairEdges = new Map<string, string[]>();
141
- edgeMap.forEach((data, edgeKey) => {
142
- const nodes = [data.source, data.target].sort();
143
- const pairKey = `${nodes[0]}_${nodes[1]}`;
144
- const existing = nodePairEdges.get(pairKey) || [];
145
- existing.push(edgeKey);
146
- nodePairEdges.set(pairKey, existing);
147
- });
148
-
149
- // Convert map to edges with label offsets
150
- const edges: AgentViewEdge[] = [];
151
-
152
- edgeMap.forEach((data, edgeKey) => {
153
- const nodes = [data.source, data.target].sort();
154
- const pairKey = `${nodes[0]}_${nodes[1]}`;
155
- const edgesInPair = nodePairEdges.get(pairKey) || [];
156
- const edgeIndex = edgesInPair.indexOf(edgeKey);
157
- const totalEdgesInPair = edgesInPair.length;
158
-
159
- // Calculate label offset (spread labels vertically if multiple edges)
160
- // Offset range: -20 to +20 pixels for up to 3 edges, more if needed
161
- let labelOffset = 0;
162
- if (totalEdgesInPair > 1) {
163
- const offsetRange = Math.min(40, totalEdgesInPair * 15);
164
- const step = offsetRange / (totalEdgesInPair - 1);
165
- labelOffset = edgeIndex * step - offsetRange / 2;
166
- }
167
-
168
- // Phase 11 Bug Fix: Calculate filtered count from actual consumption data
169
- // Count how many artifacts were actually consumed by the target agent
170
- const totalCount = data.artifact_ids.length;
171
- const consumedCount = data.artifact_ids.filter((artifactId) => {
172
- const consumers = state.consumptions.get(artifactId) || [];
173
- return consumers.includes(data.target);
174
- }).length;
175
-
176
- // Format label: "Type (total, filtered: consumed)" if filtering occurred
177
- let label = `${data.message_type} (${totalCount})`;
178
- if (consumedCount < totalCount && consumedCount > 0) {
179
- label = `${data.message_type} (${totalCount}, filtered: ${consumedCount})`;
180
- }
181
-
182
- edges.push({
183
- id: edgeKey,
184
- source: data.source,
185
- target: data.target,
186
- type: 'message_flow',
187
- label,
188
- markerEnd: {
189
- type: 'arrowclosed',
190
- width: 20,
191
- height: 20,
192
- },
193
- data: {
194
- messageType: data.message_type,
195
- messageCount: data.artifact_ids.length,
196
- artifactIds: data.artifact_ids,
197
- latestTimestamp: data.latest_timestamp,
198
- labelOffset, // Phase 11: Added for label positioning
199
- },
200
- });
201
- });
202
-
203
- return edges;
204
- }
205
-
206
- /**
207
- * Derive Blackboard View edges from dashboard state
208
- *
209
- * Algorithm (DATA_MODEL.md lines 824-853):
210
- * 1. For each completed run (status !== 'active')
211
- * 2. Create edges from consumed artifacts to produced artifacts
212
- * 3. Label with agent name
213
- * 4. Include run metadata (run_id, duration_ms)
214
- * 5. Add label offset for multiple edges between same artifacts (Phase 11 bug fix)
215
- *
216
- * Edge format:
217
- * - ID: `${consumed_id}_${produced_id}_${run_id}` (Phase 11: Added run_id for uniqueness)
218
- * - Type: 'transformation'
219
- * - Label: agent_name
220
- * - Data: { transformer_agent, run_id, duration_ms, labelOffset }
221
- *
222
- * @param state - Dashboard state with artifacts and runs
223
- * @returns Array of transformation edges
224
- */
225
- export function deriveBlackboardViewEdges(
226
- state: DashboardState
227
- ): BlackboardViewEdge[] {
228
- const tempEdges: Array<{
229
- id: string;
230
- source: string;
231
- target: string;
232
- label: string;
233
- data: {
234
- transformerAgent: string;
235
- runId: string;
236
- durationMs?: number;
237
- };
238
- }> = [];
239
-
240
- // Iterate through all runs
241
- state.runs.forEach((run) => {
242
- // Skip active runs (only process completed or error runs)
243
- if (run.status === 'active') {
244
- return;
245
- }
246
-
247
- // Skip runs with no consumed or produced artifacts
248
- if (
249
- run.consumed_artifacts.length === 0 ||
250
- run.produced_artifacts.length === 0
251
- ) {
252
- return;
253
- }
254
-
255
- // Create edges for each consumed × produced pair
256
- run.consumed_artifacts.forEach((consumedId) => {
257
- run.produced_artifacts.forEach((producedId) => {
258
- // Phase 11: Include run_id in edge ID to make it unique per transformation
259
- const edgeId = `${consumedId}_${producedId}_${run.run_id}`;
260
-
261
- tempEdges.push({
262
- id: edgeId,
263
- source: consumedId,
264
- target: producedId,
265
- label: run.agent_name,
266
- data: {
267
- transformerAgent: run.agent_name,
268
- runId: run.run_id,
269
- durationMs: run.duration_ms,
270
- },
271
- });
272
- });
273
- });
274
- });
275
-
276
- // Phase 11 Bug Fix: Calculate label offsets for edges between same artifact pairs
277
- // Group edges by artifact pair to detect multiple transformations
278
- // Use canonical pair key (sorted) so A→B and B→A are treated as same pair
279
- const artifactPairEdges = new Map<string, string[]>();
280
- tempEdges.forEach((edge) => {
281
- const nodes = [edge.source, edge.target].sort();
282
- const pairKey = `${nodes[0]}_${nodes[1]}`;
283
- const existing = artifactPairEdges.get(pairKey) || [];
284
- existing.push(edge.id);
285
- artifactPairEdges.set(pairKey, existing);
286
- });
287
-
288
- // Convert to final edges with label offsets
289
- const edges: BlackboardViewEdge[] = tempEdges.map((edge) => {
290
- const nodes = [edge.source, edge.target].sort();
291
- const pairKey = `${nodes[0]}_${nodes[1]}`;
292
- const edgesInPair = artifactPairEdges.get(pairKey) || [];
293
- const edgeIndex = edgesInPair.indexOf(edge.id);
294
- const totalEdgesInPair = edgesInPair.length;
295
-
296
- // Calculate label offset (spread labels vertically if multiple transformations)
297
- let labelOffset = 0;
298
- if (totalEdgesInPair > 1) {
299
- const offsetRange = Math.min(40, totalEdgesInPair * 15);
300
- const step = offsetRange / (totalEdgesInPair - 1);
301
- labelOffset = edgeIndex * step - offsetRange / 2;
302
- }
303
-
304
- return {
305
- id: edge.id,
306
- source: edge.source,
307
- target: edge.target,
308
- type: 'transformation',
309
- label: edge.label,
310
- markerEnd: {
311
- type: 'arrowclosed',
312
- width: 20,
313
- height: 20,
314
- },
315
- data: {
316
- ...edge.data,
317
- labelOffset, // Phase 11: Added for label positioning
318
- },
319
- };
320
- });
321
-
322
- return edges;
323
- }