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,5 +1,5 @@
|
|
|
1
1
|
import { create } from 'zustand';
|
|
2
|
-
import { devtools } from 'zustand/middleware';
|
|
2
|
+
import { devtools, persist } from 'zustand/middleware';
|
|
3
3
|
import type { ModuleInstance } from '../types/modules';
|
|
4
4
|
|
|
5
5
|
interface ModuleState {
|
|
@@ -15,43 +15,61 @@ interface ModuleState {
|
|
|
15
15
|
|
|
16
16
|
export const useModuleStore = create<ModuleState>()(
|
|
17
17
|
devtools(
|
|
18
|
-
(
|
|
19
|
-
|
|
18
|
+
persist<ModuleState>(
|
|
19
|
+
(set) => ({
|
|
20
|
+
instances: new Map(),
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
addModule: (module: ModuleInstance) =>
|
|
23
|
+
set((state) => {
|
|
24
|
+
const instances = new Map(state.instances);
|
|
25
|
+
instances.set(module.id, module);
|
|
26
|
+
return { instances };
|
|
27
|
+
}),
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
updateModule: (id: string, updates: Partial<Omit<ModuleInstance, 'id' | 'type'>>) =>
|
|
30
|
+
set((state) => {
|
|
31
|
+
const instances = new Map(state.instances);
|
|
32
|
+
const existing = instances.get(id);
|
|
33
|
+
if (existing) {
|
|
34
|
+
instances.set(id, { ...existing, ...updates });
|
|
35
|
+
}
|
|
36
|
+
return { instances };
|
|
37
|
+
}),
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
removeModule: (id: string) =>
|
|
40
|
+
set((state) => {
|
|
41
|
+
const instances = new Map(state.instances);
|
|
42
|
+
instances.delete(id);
|
|
43
|
+
return { instances };
|
|
44
|
+
}),
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
toggleVisibility: (id: string) =>
|
|
47
|
+
set((state) => {
|
|
48
|
+
const instances = new Map(state.instances);
|
|
49
|
+
const existing = instances.get(id);
|
|
50
|
+
if (existing) {
|
|
51
|
+
instances.set(id, { ...existing, visible: !existing.visible });
|
|
52
|
+
}
|
|
53
|
+
return { instances };
|
|
54
|
+
}),
|
|
55
|
+
}),
|
|
56
|
+
{
|
|
57
|
+
name: 'flock-module-state',
|
|
58
|
+
partialize: (state) => ({
|
|
59
|
+
instances: Array.from(state.instances.entries()),
|
|
60
|
+
}) as any,
|
|
61
|
+
merge: (persistedState: any, currentState: any) => {
|
|
62
|
+
// Convert instances array back to Map
|
|
63
|
+
if (persistedState?.instances && Array.isArray(persistedState.instances)) {
|
|
64
|
+
persistedState.instances = new Map(persistedState.instances);
|
|
51
65
|
}
|
|
52
|
-
return {
|
|
53
|
-
|
|
54
|
-
|
|
66
|
+
return {
|
|
67
|
+
...currentState,
|
|
68
|
+
...persistedState,
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
),
|
|
55
73
|
{ name: 'moduleStore' }
|
|
56
74
|
)
|
|
57
75
|
);
|
|
@@ -40,17 +40,17 @@ interface UIState {
|
|
|
40
40
|
|
|
41
41
|
export const useUIStore = create<UIState>()(
|
|
42
42
|
devtools(
|
|
43
|
-
persist(
|
|
43
|
+
persist<UIState>(
|
|
44
44
|
(set) => ({
|
|
45
45
|
mode: 'agent',
|
|
46
|
-
setMode: (mode) => set({ mode }),
|
|
46
|
+
setMode: (mode: VisualizationMode) => set({ mode }),
|
|
47
47
|
|
|
48
48
|
selectedNodeIds: new Set(),
|
|
49
|
-
selectNode: (nodeId) =>
|
|
49
|
+
selectNode: (nodeId: string) =>
|
|
50
50
|
set((state) => ({
|
|
51
51
|
selectedNodeIds: new Set(state.selectedNodeIds).add(nodeId),
|
|
52
52
|
})),
|
|
53
|
-
deselectNode: (nodeId) =>
|
|
53
|
+
deselectNode: (nodeId: string) =>
|
|
54
54
|
set((state) => {
|
|
55
55
|
const ids = new Set(state.selectedNodeIds);
|
|
56
56
|
ids.delete(nodeId);
|
|
@@ -59,7 +59,7 @@ export const useUIStore = create<UIState>()(
|
|
|
59
59
|
clearSelection: () => set({ selectedNodeIds: new Set() }),
|
|
60
60
|
|
|
61
61
|
detailWindows: new Map(),
|
|
62
|
-
openDetailWindow: (nodeId) =>
|
|
62
|
+
openDetailWindow: (nodeId: string) =>
|
|
63
63
|
set((state) => {
|
|
64
64
|
const windows = new Map(state.detailWindows);
|
|
65
65
|
if (!windows.has(nodeId)) {
|
|
@@ -72,13 +72,13 @@ export const useUIStore = create<UIState>()(
|
|
|
72
72
|
}
|
|
73
73
|
return { detailWindows: windows };
|
|
74
74
|
}),
|
|
75
|
-
closeDetailWindow: (nodeId) =>
|
|
75
|
+
closeDetailWindow: (nodeId: string) =>
|
|
76
76
|
set((state) => {
|
|
77
77
|
const windows = new Map(state.detailWindows);
|
|
78
78
|
windows.delete(nodeId);
|
|
79
79
|
return { detailWindows: windows };
|
|
80
80
|
}),
|
|
81
|
-
updateDetailWindow: (nodeId, updates) =>
|
|
81
|
+
updateDetailWindow: (nodeId: string, updates: Partial<DetailWindow>) =>
|
|
82
82
|
set((state) => {
|
|
83
83
|
const windows = new Map(state.detailWindows);
|
|
84
84
|
const existing = windows.get(nodeId);
|
|
@@ -89,20 +89,32 @@ export const useUIStore = create<UIState>()(
|
|
|
89
89
|
}),
|
|
90
90
|
|
|
91
91
|
layoutDirection: 'TB',
|
|
92
|
-
setLayoutDirection: (direction) => set({ layoutDirection: direction }),
|
|
92
|
+
setLayoutDirection: (direction: 'TB' | 'LR') => set({ layoutDirection: direction }),
|
|
93
93
|
autoLayoutEnabled: true,
|
|
94
|
-
setAutoLayoutEnabled: (enabled) => set({ autoLayoutEnabled: enabled }),
|
|
94
|
+
setAutoLayoutEnabled: (enabled: boolean) => set({ autoLayoutEnabled: enabled }),
|
|
95
95
|
|
|
96
96
|
defaultTab: 'liveOutput',
|
|
97
|
-
setDefaultTab: (tab) => set({ defaultTab: tab }),
|
|
97
|
+
setDefaultTab: (tab: 'liveOutput' | 'messageHistory' | 'runStatus') => set({ defaultTab: tab }),
|
|
98
98
|
}),
|
|
99
99
|
{
|
|
100
100
|
name: 'ui-storage',
|
|
101
101
|
partialize: (state) => ({
|
|
102
|
+
mode: state.mode,
|
|
103
|
+
detailWindows: Array.from(state.detailWindows.entries()),
|
|
102
104
|
defaultTab: state.defaultTab,
|
|
103
105
|
layoutDirection: state.layoutDirection,
|
|
104
106
|
autoLayoutEnabled: state.autoLayoutEnabled,
|
|
105
|
-
}),
|
|
107
|
+
}) as any,
|
|
108
|
+
merge: (persistedState: any, currentState: any) => {
|
|
109
|
+
// Convert detailWindows array back to Map
|
|
110
|
+
if (persistedState?.detailWindows && Array.isArray(persistedState.detailWindows)) {
|
|
111
|
+
persistedState.detailWindows = new Map(persistedState.detailWindows);
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
...currentState,
|
|
115
|
+
...persistedState,
|
|
116
|
+
};
|
|
117
|
+
},
|
|
106
118
|
}
|
|
107
119
|
),
|
|
108
120
|
{ name: 'uiStore' }
|
|
@@ -1,20 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export interface Agent {
|
|
4
|
-
id: string;
|
|
5
|
-
name: string;
|
|
6
|
-
status: 'idle' | 'running' | 'error';
|
|
7
|
-
subscriptions: string[];
|
|
8
|
-
lastActive: number;
|
|
9
|
-
sentCount: number;
|
|
10
|
-
recvCount: number;
|
|
11
|
-
position?: { x: number; y: number };
|
|
12
|
-
outputTypes?: string[]; // Artifact types this agent produces
|
|
13
|
-
receivedByType?: Record<string, number>; // Count of messages received per type
|
|
14
|
-
sentByType?: Record<string, number>; // Count of messages sent per type
|
|
15
|
-
streamingTokens?: string[]; // Last 6 streaming tokens for news ticker effect
|
|
16
|
-
}
|
|
17
|
-
|
|
1
|
+
// Legacy types (still used during migration for events, WebSocket handlers)
|
|
18
2
|
export interface Message {
|
|
19
3
|
id: string;
|
|
20
4
|
type: string;
|
|
@@ -26,37 +10,86 @@ export interface Message {
|
|
|
26
10
|
visibilityKind?: string;
|
|
27
11
|
partitionKey?: string | null;
|
|
28
12
|
version?: number;
|
|
29
|
-
isStreaming?: boolean;
|
|
30
|
-
streamingText?: string;
|
|
13
|
+
isStreaming?: boolean;
|
|
14
|
+
streamingText?: string;
|
|
31
15
|
consumedBy?: string[];
|
|
32
16
|
}
|
|
33
17
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
sentCount: number;
|
|
40
|
-
recvCount: number;
|
|
41
|
-
receivedByType?: Record<string, number>;
|
|
42
|
-
sentByType?: Record<string, number>;
|
|
43
|
-
streamingTokens?: string[]; // Last 6 streaming tokens for news ticker effect
|
|
18
|
+
// New backend API types (Phase 1 - Spec 002)
|
|
19
|
+
export interface GraphRequest {
|
|
20
|
+
viewMode: 'agent' | 'blackboard';
|
|
21
|
+
filters: GraphFilters;
|
|
22
|
+
options?: GraphRequestOptions;
|
|
44
23
|
}
|
|
45
24
|
|
|
46
|
-
export interface
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
25
|
+
export interface GraphFilters {
|
|
26
|
+
correlation_id?: string | null;
|
|
27
|
+
time_range: TimeRangeFilter;
|
|
28
|
+
artifactTypes: string[];
|
|
29
|
+
producers: string[];
|
|
30
|
+
tags: string[];
|
|
31
|
+
visibility: string[];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface TimeRangeFilter {
|
|
35
|
+
preset: 'last10min' | 'last5min' | 'last1hour' | 'all' | 'custom';
|
|
36
|
+
start?: string | null;
|
|
37
|
+
end?: string | null;
|
|
57
38
|
}
|
|
58
39
|
|
|
59
|
-
export
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
40
|
+
export interface GraphRequestOptions {
|
|
41
|
+
include_statistics?: boolean;
|
|
42
|
+
label_offset_strategy?: 'stack' | 'none';
|
|
43
|
+
limit?: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface GraphSnapshot {
|
|
47
|
+
generatedAt: string;
|
|
48
|
+
viewMode: 'agent' | 'blackboard';
|
|
49
|
+
filters: GraphFilters;
|
|
50
|
+
nodes: GraphNode[];
|
|
51
|
+
edges: GraphEdge[];
|
|
52
|
+
statistics: GraphStatistics | null;
|
|
53
|
+
totalArtifacts: number;
|
|
54
|
+
truncated: boolean;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface GraphNode {
|
|
58
|
+
id: string;
|
|
59
|
+
type: 'agent' | 'message';
|
|
60
|
+
data: Record<string, any>;
|
|
61
|
+
position: { x: number; y: number };
|
|
62
|
+
hidden: boolean;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface GraphEdge {
|
|
66
|
+
id: string;
|
|
67
|
+
source: string;
|
|
68
|
+
target: string;
|
|
69
|
+
type: 'message_flow' | 'transformation';
|
|
70
|
+
label?: string | null;
|
|
71
|
+
data: Record<string, any>;
|
|
72
|
+
markerEnd?: { type: string; width: number; height: number };
|
|
73
|
+
hidden: boolean;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface GraphStatistics {
|
|
77
|
+
producedByAgent: Record<string, GraphAgentMetrics>;
|
|
78
|
+
consumedByAgent: Record<string, GraphAgentMetrics>;
|
|
79
|
+
artifactSummary: ArtifactSummary;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface GraphAgentMetrics {
|
|
83
|
+
total: number;
|
|
84
|
+
byType: Record<string, number>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface ArtifactSummary {
|
|
88
|
+
total: number;
|
|
89
|
+
by_type: Record<string, number>;
|
|
90
|
+
by_producer: Record<string, number>;
|
|
91
|
+
by_visibility: Record<string, number>;
|
|
92
|
+
tag_counts: Record<string, number>;
|
|
93
|
+
earliest_created_at: string;
|
|
94
|
+
latest_created_at: string;
|
|
95
|
+
}
|
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Message } from '../types/graph';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// UI Optimization Migration (Phase 4.1 - Spec 002): OLD Phase 1 mock data (unused)
|
|
4
|
+
// Kept for potential future testing, but Agent type no longer exists
|
|
5
|
+
type LegacyAgent = {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
status: string;
|
|
9
|
+
subscriptions: string[];
|
|
10
|
+
lastActive: number;
|
|
11
|
+
sentCount: number;
|
|
12
|
+
recvCount: number;
|
|
13
|
+
position: { x: number; y: number };
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const mockAgents: LegacyAgent[] = [
|
|
4
17
|
{
|
|
5
18
|
id: 'movie',
|
|
6
19
|
name: 'movie',
|
|
@@ -46,7 +59,7 @@ export const mockMessages: Message[] = [
|
|
|
46
59
|
id: 'msg-2',
|
|
47
60
|
type: 'Movie',
|
|
48
61
|
payload: { title: 'Inception', year: 2010, genre: 'Sci-Fi' },
|
|
49
|
-
timestamp: Date.now() -
|
|
62
|
+
timestamp: Date.now() - 8344,
|
|
50
63
|
correlationId: 'corr-123',
|
|
51
64
|
producedBy: 'movie',
|
|
52
65
|
},
|
flock/frontend/vite.config.ts
CHANGED
|
@@ -13,11 +13,11 @@ export default defineConfig({
|
|
|
13
13
|
port: 5173,
|
|
14
14
|
proxy: {
|
|
15
15
|
'/api': {
|
|
16
|
-
target: 'http://localhost:
|
|
16
|
+
target: 'http://localhost:8344',
|
|
17
17
|
changeOrigin: true,
|
|
18
18
|
},
|
|
19
19
|
'/ws': {
|
|
20
|
-
target: 'ws://localhost:
|
|
20
|
+
target: 'ws://localhost:8344',
|
|
21
21
|
ws: true,
|
|
22
22
|
},
|
|
23
23
|
},
|
flock/orchestrator.py
CHANGED
|
@@ -6,10 +6,11 @@ import asyncio
|
|
|
6
6
|
import logging
|
|
7
7
|
import os
|
|
8
8
|
from asyncio import Task
|
|
9
|
-
from collections.abc import Iterable, Mapping, Sequence
|
|
9
|
+
from collections.abc import AsyncGenerator, Iterable, Mapping, Sequence
|
|
10
10
|
from contextlib import asynccontextmanager
|
|
11
11
|
from datetime import datetime, timezone
|
|
12
|
-
from
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import TYPE_CHECKING, Any
|
|
13
14
|
from uuid import uuid4
|
|
14
15
|
|
|
15
16
|
from opentelemetry import trace
|
|
@@ -545,14 +546,20 @@ class Flock(metaclass=AutoTracedMeta):
|
|
|
545
546
|
return self
|
|
546
547
|
|
|
547
548
|
async def serve(
|
|
548
|
-
self,
|
|
549
|
+
self,
|
|
550
|
+
*,
|
|
551
|
+
dashboard: bool = False,
|
|
552
|
+
dashboard_v2: bool = False,
|
|
553
|
+
host: str = "127.0.0.1",
|
|
554
|
+
port: int = 8344,
|
|
549
555
|
) -> None:
|
|
550
556
|
"""Start HTTP service for the orchestrator (blocking).
|
|
551
557
|
|
|
552
558
|
Args:
|
|
553
559
|
dashboard: Enable real-time dashboard with WebSocket support (default: False)
|
|
560
|
+
dashboard_v2: Launch the new dashboard v2 frontend (implies dashboard=True)
|
|
554
561
|
host: Host to bind to (default: "127.0.0.1")
|
|
555
|
-
port: Port to bind to (default:
|
|
562
|
+
port: Port to bind to (default: 8344)
|
|
556
563
|
|
|
557
564
|
Examples:
|
|
558
565
|
# Basic HTTP API (no dashboard) - runs until interrupted
|
|
@@ -561,6 +568,9 @@ class Flock(metaclass=AutoTracedMeta):
|
|
|
561
568
|
# With dashboard (WebSocket + browser launch) - runs until interrupted
|
|
562
569
|
await orchestrator.serve(dashboard=True)
|
|
563
570
|
"""
|
|
571
|
+
if dashboard_v2:
|
|
572
|
+
dashboard = True
|
|
573
|
+
|
|
564
574
|
if not dashboard:
|
|
565
575
|
# Standard service without dashboard
|
|
566
576
|
from flock.service import BlackboardHTTPService
|
|
@@ -577,8 +587,9 @@ class Flock(metaclass=AutoTracedMeta):
|
|
|
577
587
|
|
|
578
588
|
# Create dashboard components
|
|
579
589
|
websocket_manager = WebSocketManager()
|
|
580
|
-
event_collector = DashboardEventCollector()
|
|
590
|
+
event_collector = DashboardEventCollector(store=self.store)
|
|
581
591
|
event_collector.set_websocket_manager(websocket_manager)
|
|
592
|
+
await event_collector.load_persistent_snapshots()
|
|
582
593
|
|
|
583
594
|
# Store collector reference for agents added later
|
|
584
595
|
self._dashboard_collector = event_collector
|
|
@@ -589,7 +600,13 @@ class Flock(metaclass=AutoTracedMeta):
|
|
|
589
600
|
agent.utilities.insert(0, event_collector)
|
|
590
601
|
|
|
591
602
|
# Start dashboard launcher (npm process + browser)
|
|
592
|
-
|
|
603
|
+
launcher_kwargs: dict[str, Any] = {"port": port}
|
|
604
|
+
if dashboard_v2:
|
|
605
|
+
dashboard_pkg_dir = Path(__file__).parent / "dashboard"
|
|
606
|
+
launcher_kwargs["frontend_dir"] = dashboard_pkg_dir.parent / "frontend_v2"
|
|
607
|
+
launcher_kwargs["static_dir"] = dashboard_pkg_dir / "static_v2"
|
|
608
|
+
|
|
609
|
+
launcher = DashboardLauncher(**launcher_kwargs)
|
|
593
610
|
launcher.start()
|
|
594
611
|
|
|
595
612
|
# Create dashboard HTTP service
|
|
@@ -597,6 +614,7 @@ class Flock(metaclass=AutoTracedMeta):
|
|
|
597
614
|
orchestrator=self,
|
|
598
615
|
websocket_manager=websocket_manager,
|
|
599
616
|
event_collector=event_collector,
|
|
617
|
+
use_v2=dashboard_v2,
|
|
600
618
|
)
|
|
601
619
|
|
|
602
620
|
# Store launcher for cleanup
|
flock/service.py
CHANGED
|
@@ -257,14 +257,14 @@ class BlackboardHTTPService:
|
|
|
257
257
|
return PlainTextResponse("\n".join(lines))
|
|
258
258
|
|
|
259
259
|
def run(
|
|
260
|
-
self, host: str = "127.0.0.1", port: int =
|
|
260
|
+
self, host: str = "127.0.0.1", port: int = 8344
|
|
261
261
|
) -> None: # pragma: no cover - manual execution
|
|
262
262
|
import uvicorn
|
|
263
263
|
|
|
264
264
|
uvicorn.run(self.app, host=host, port=port)
|
|
265
265
|
|
|
266
266
|
async def run_async(
|
|
267
|
-
self, host: str = "127.0.0.1", port: int =
|
|
267
|
+
self, host: str = "127.0.0.1", port: int = 8344
|
|
268
268
|
) -> None: # pragma: no cover - manual execution
|
|
269
269
|
"""Run the service asynchronously (for use within async context)."""
|
|
270
270
|
import uvicorn
|