flock-core 0.5.0b65__py3-none-any.whl → 0.5.0b70__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/cli.py +74 -2
- flock/engines/dspy_engine.py +40 -4
- flock/examples.py +4 -1
- flock/frontend/README.md +15 -1
- flock/frontend/package-lock.json +2 -2
- flock/frontend/package.json +1 -1
- flock/frontend/src/App.tsx +74 -6
- flock/frontend/src/__tests__/e2e/critical-scenarios.test.tsx +4 -5
- flock/frontend/src/__tests__/integration/filtering-e2e.test.tsx +7 -3
- flock/frontend/src/components/filters/ArtifactTypeFilter.tsx +21 -0
- flock/frontend/src/components/filters/FilterFlyout.module.css +104 -0
- flock/frontend/src/components/filters/FilterFlyout.tsx +80 -0
- flock/frontend/src/components/filters/FilterPills.module.css +186 -45
- flock/frontend/src/components/filters/FilterPills.test.tsx +115 -99
- flock/frontend/src/components/filters/FilterPills.tsx +120 -44
- flock/frontend/src/components/filters/ProducerFilter.tsx +21 -0
- flock/frontend/src/components/filters/SavedFiltersControl.module.css +60 -0
- flock/frontend/src/components/filters/SavedFiltersControl.test.tsx +158 -0
- flock/frontend/src/components/filters/SavedFiltersControl.tsx +159 -0
- flock/frontend/src/components/filters/TagFilter.tsx +21 -0
- flock/frontend/src/components/filters/TimeRangeFilter.module.css +24 -0
- flock/frontend/src/components/filters/TimeRangeFilter.tsx +6 -1
- flock/frontend/src/components/filters/VisibilityFilter.tsx +21 -0
- flock/frontend/src/components/graph/GraphCanvas.tsx +24 -0
- flock/frontend/src/components/layout/DashboardLayout.css +13 -0
- flock/frontend/src/components/layout/DashboardLayout.tsx +8 -24
- flock/frontend/src/components/modules/HistoricalArtifactsModule.module.css +288 -0
- flock/frontend/src/components/modules/HistoricalArtifactsModule.tsx +460 -0
- flock/frontend/src/components/modules/HistoricalArtifactsModuleWrapper.tsx +13 -0
- flock/frontend/src/components/modules/ModuleRegistry.ts +7 -1
- flock/frontend/src/components/modules/registerModules.ts +9 -10
- flock/frontend/src/hooks/useModules.ts +11 -1
- flock/frontend/src/services/api.ts +140 -0
- flock/frontend/src/services/indexeddb.ts +56 -2
- flock/frontend/src/services/websocket.ts +129 -0
- flock/frontend/src/store/filterStore.test.ts +105 -185
- flock/frontend/src/store/filterStore.ts +173 -26
- flock/frontend/src/store/graphStore.test.ts +19 -0
- flock/frontend/src/store/graphStore.ts +166 -27
- flock/frontend/src/types/filters.ts +34 -1
- flock/frontend/src/types/graph.ts +7 -0
- flock/frontend/src/utils/artifacts.ts +24 -0
- flock/orchestrator.py +23 -1
- flock/service.py +146 -9
- flock/store.py +971 -24
- {flock_core-0.5.0b65.dist-info → flock_core-0.5.0b70.dist-info}/METADATA +26 -1
- {flock_core-0.5.0b65.dist-info → flock_core-0.5.0b70.dist-info}/RECORD +50 -43
- flock/frontend/src/components/filters/FilterBar.module.css +0 -29
- flock/frontend/src/components/filters/FilterBar.test.tsx +0 -133
- flock/frontend/src/components/filters/FilterBar.tsx +0 -33
- flock/frontend/src/components/modules/EventLogModule.test.tsx +0 -401
- flock/frontend/src/components/modules/EventLogModule.tsx +0 -396
- flock/frontend/src/components/modules/EventLogModuleWrapper.tsx +0 -17
- {flock_core-0.5.0b65.dist-info → flock_core-0.5.0b70.dist-info}/WHEEL +0 -0
- {flock_core-0.5.0b65.dist-info → flock_core-0.5.0b70.dist-info}/entry_points.txt +0 -0
- {flock_core-0.5.0b65.dist-info → flock_core-0.5.0b70.dist-info}/licenses/LICENSE +0 -0
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* Base URL defaults to /api for same-origin requests.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import type { ArtifactSummary } from '../types/filters';
|
|
11
|
+
|
|
10
12
|
const BASE_URL = import.meta.env.VITE_API_BASE_URL || '/api';
|
|
11
13
|
|
|
12
14
|
export interface ArtifactType {
|
|
@@ -47,6 +49,56 @@ export interface AgentsResponse {
|
|
|
47
49
|
agents: Agent[];
|
|
48
50
|
}
|
|
49
51
|
|
|
52
|
+
export interface ArtifactListItem {
|
|
53
|
+
id: string;
|
|
54
|
+
type: string;
|
|
55
|
+
payload: Record<string, any>;
|
|
56
|
+
produced_by: string;
|
|
57
|
+
created_at: string;
|
|
58
|
+
correlation_id: string | null;
|
|
59
|
+
partition_key: string | null;
|
|
60
|
+
tags: string[];
|
|
61
|
+
visibility: { kind: string; [key: string]: any };
|
|
62
|
+
visibility_kind?: string;
|
|
63
|
+
version?: number;
|
|
64
|
+
consumptions?: ArtifactConsumption[];
|
|
65
|
+
consumed_by?: string[];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface ArtifactConsumption {
|
|
69
|
+
artifact_id: string;
|
|
70
|
+
consumer: string;
|
|
71
|
+
run_id: string | null;
|
|
72
|
+
correlation_id: string | null;
|
|
73
|
+
consumed_at: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface ArtifactListResponse {
|
|
77
|
+
items: ArtifactListItem[];
|
|
78
|
+
pagination: {
|
|
79
|
+
limit: number;
|
|
80
|
+
offset: number;
|
|
81
|
+
total: number;
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface ArtifactSummaryResponse {
|
|
86
|
+
summary: ArtifactSummary;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface ArtifactQueryOptions {
|
|
90
|
+
types?: string[];
|
|
91
|
+
producers?: string[];
|
|
92
|
+
correlationId?: string | null;
|
|
93
|
+
tags?: string[];
|
|
94
|
+
visibility?: string[];
|
|
95
|
+
from?: string;
|
|
96
|
+
to?: string;
|
|
97
|
+
limit?: number;
|
|
98
|
+
offset?: number;
|
|
99
|
+
embedMeta?: boolean;
|
|
100
|
+
}
|
|
101
|
+
|
|
50
102
|
export interface ErrorResponse {
|
|
51
103
|
error: string;
|
|
52
104
|
message: string;
|
|
@@ -211,3 +263,91 @@ export async function invokeAgent(agentName: string): Promise<InvokeResponse> {
|
|
|
211
263
|
throw new Error('Failed to connect to API server');
|
|
212
264
|
}
|
|
213
265
|
}
|
|
266
|
+
|
|
267
|
+
const buildArtifactQuery = (options: ArtifactQueryOptions): string => {
|
|
268
|
+
const params = new URLSearchParams();
|
|
269
|
+
|
|
270
|
+
options.types?.forEach((value) => params.append('type', value));
|
|
271
|
+
options.producers?.forEach((value) => params.append('produced_by', value));
|
|
272
|
+
options.tags?.forEach((value) => params.append('tag', value));
|
|
273
|
+
options.visibility?.forEach((value) => params.append('visibility', value));
|
|
274
|
+
|
|
275
|
+
if (options.correlationId) {
|
|
276
|
+
params.append('correlation_id', options.correlationId);
|
|
277
|
+
}
|
|
278
|
+
if (options.from) {
|
|
279
|
+
params.append('from', options.from);
|
|
280
|
+
}
|
|
281
|
+
if (options.to) {
|
|
282
|
+
params.append('to', options.to);
|
|
283
|
+
}
|
|
284
|
+
if (typeof options.limit === 'number') {
|
|
285
|
+
params.append('limit', String(options.limit));
|
|
286
|
+
}
|
|
287
|
+
if (typeof options.offset === 'number') {
|
|
288
|
+
params.append('offset', String(options.offset));
|
|
289
|
+
}
|
|
290
|
+
if (options.embedMeta) {
|
|
291
|
+
params.append('embed_meta', 'true');
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return params.toString();
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
export async function fetchArtifacts(options: ArtifactQueryOptions = {}): Promise<ArtifactListResponse> {
|
|
298
|
+
const query = buildArtifactQuery(options);
|
|
299
|
+
|
|
300
|
+
try {
|
|
301
|
+
const response = await fetch(`${BASE_URL}/v1/artifacts${query ? `?${query}` : ''}`, {
|
|
302
|
+
method: 'GET',
|
|
303
|
+
headers: {
|
|
304
|
+
'Content-Type': 'application/json',
|
|
305
|
+
},
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
if (!response.ok) {
|
|
309
|
+
const errorData = await response.json().catch(() => ({
|
|
310
|
+
error: 'Unknown error',
|
|
311
|
+
message: 'Failed to fetch artifacts',
|
|
312
|
+
}));
|
|
313
|
+
throw new ApiError(response.status, errorData);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const data: ArtifactListResponse = await response.json();
|
|
317
|
+
return data;
|
|
318
|
+
} catch (error) {
|
|
319
|
+
if (error instanceof ApiError) {
|
|
320
|
+
throw error;
|
|
321
|
+
}
|
|
322
|
+
throw new Error('Failed to connect to API server');
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export async function fetchArtifactSummary(options: ArtifactQueryOptions = {}): Promise<ArtifactSummary> {
|
|
327
|
+
const query = buildArtifactQuery(options);
|
|
328
|
+
|
|
329
|
+
try {
|
|
330
|
+
const response = await fetch(`${BASE_URL}/v1/artifacts/summary${query ? `?${query}` : ''}`, {
|
|
331
|
+
method: 'GET',
|
|
332
|
+
headers: {
|
|
333
|
+
'Content-Type': 'application/json',
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
if (!response.ok) {
|
|
338
|
+
const errorData = await response.json().catch(() => ({
|
|
339
|
+
error: 'Unknown error',
|
|
340
|
+
message: 'Failed to fetch artifact summary',
|
|
341
|
+
}));
|
|
342
|
+
throw new ApiError(response.status, errorData);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const data: ArtifactSummaryResponse = await response.json();
|
|
346
|
+
return data.summary;
|
|
347
|
+
} catch (error) {
|
|
348
|
+
if (error instanceof ApiError) {
|
|
349
|
+
throw error;
|
|
350
|
+
}
|
|
351
|
+
throw new Error('Failed to connect to API server');
|
|
352
|
+
}
|
|
353
|
+
}
|
|
@@ -27,6 +27,8 @@
|
|
|
27
27
|
// Note: idb library is available for production use, but we use raw IndexedDB API
|
|
28
28
|
// for better compatibility with test mocks
|
|
29
29
|
|
|
30
|
+
import type { FilterSnapshot } from '../types/filters';
|
|
31
|
+
|
|
30
32
|
// Database constants
|
|
31
33
|
const DB_NAME = 'flock_dashboard_v1';
|
|
32
34
|
const DB_VERSION = 1;
|
|
@@ -128,8 +130,8 @@ interface SessionRecord {
|
|
|
128
130
|
export interface FilterRecord {
|
|
129
131
|
filter_id: string; // PRIMARY KEY
|
|
130
132
|
name: string;
|
|
131
|
-
filters:
|
|
132
|
-
created_at:
|
|
133
|
+
filters: FilterSnapshot;
|
|
134
|
+
created_at: number;
|
|
133
135
|
}
|
|
134
136
|
|
|
135
137
|
// Helper to wrap IDBRequest in Promise
|
|
@@ -430,6 +432,58 @@ export class IndexedDBService {
|
|
|
430
432
|
}
|
|
431
433
|
}
|
|
432
434
|
|
|
435
|
+
// ============================================================================
|
|
436
|
+
// CRUD Operations - Filters Store
|
|
437
|
+
// ============================================================================
|
|
438
|
+
|
|
439
|
+
async saveFilterPreset(record: FilterRecord): Promise<void> {
|
|
440
|
+
if (!this.db) {
|
|
441
|
+
this.inMemoryStore.get('filters')?.set(record.filter_id, record);
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
try {
|
|
446
|
+
const tx = this.db.transaction('filters', 'readwrite');
|
|
447
|
+
const store = tx.objectStore('filters');
|
|
448
|
+
await promisifyRequest(store.put(record));
|
|
449
|
+
} catch (error) {
|
|
450
|
+
console.error('[IndexedDB] Failed to save filter preset:', error);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
async getAllFilterPresets(): Promise<FilterRecord[]> {
|
|
455
|
+
if (!this.db) {
|
|
456
|
+
const filters = this.inMemoryStore.get('filters');
|
|
457
|
+
if (!filters) return [];
|
|
458
|
+
return Array.from(filters.values()).sort((a, b) => b.created_at - a.created_at);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
try {
|
|
462
|
+
const tx = this.db.transaction('filters', 'readonly');
|
|
463
|
+
const store = tx.objectStore('filters');
|
|
464
|
+
const records: FilterRecord[] = await promisifyRequest(store.getAll());
|
|
465
|
+
return records.sort((a, b) => b.created_at - a.created_at);
|
|
466
|
+
} catch (error) {
|
|
467
|
+
console.error('[IndexedDB] Failed to load filter presets:', error);
|
|
468
|
+
return [];
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
async deleteFilterPreset(filterId: string): Promise<void> {
|
|
473
|
+
if (!this.db) {
|
|
474
|
+
this.inMemoryStore.get('filters')?.delete(filterId);
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
try {
|
|
479
|
+
const tx = this.db.transaction('filters', 'readwrite');
|
|
480
|
+
const store = tx.objectStore('filters');
|
|
481
|
+
await promisifyRequest(store.delete(filterId));
|
|
482
|
+
} catch (error) {
|
|
483
|
+
console.error('[IndexedDB] Failed to delete filter preset:', error);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
433
487
|
// ============================================================================
|
|
434
488
|
// CRUD Operations - Runs Store
|
|
435
489
|
// ============================================================================
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { useWSStore } from '../store/wsStore';
|
|
2
2
|
import { useGraphStore } from '../store/graphStore';
|
|
3
|
+
import { useFilterStore } from '../store/filterStore';
|
|
4
|
+
import { useUIStore } from '../store/uiStore';
|
|
3
5
|
|
|
4
6
|
interface WebSocketMessage {
|
|
5
7
|
event_type: 'agent_activated' | 'message_published' | 'streaming_output' | 'agent_completed' | 'agent_error';
|
|
@@ -51,6 +53,109 @@ export class WebSocketClient {
|
|
|
51
53
|
this.setupEventHandlers();
|
|
52
54
|
}
|
|
53
55
|
|
|
56
|
+
private updateFilterStateFromPublishedMessage(data: any): void {
|
|
57
|
+
const filterStore = useFilterStore.getState();
|
|
58
|
+
|
|
59
|
+
const artifactType = typeof data.artifact_type === 'string' ? data.artifact_type : '';
|
|
60
|
+
const producer = typeof data.produced_by === 'string' ? data.produced_by : '';
|
|
61
|
+
const tags = Array.isArray(data.tags) ? data.tags.filter((tag: unknown) => typeof tag === 'string' && tag.length > 0) : [];
|
|
62
|
+
const visibilityKind =
|
|
63
|
+
(typeof data.visibility === 'object' && data.visibility && typeof data.visibility.kind === 'string'
|
|
64
|
+
? data.visibility.kind
|
|
65
|
+
: undefined) ||
|
|
66
|
+
(typeof data.visibility_kind === 'string' ? data.visibility_kind : undefined) ||
|
|
67
|
+
(typeof data.visibility === 'string' ? data.visibility : undefined) ||
|
|
68
|
+
'';
|
|
69
|
+
|
|
70
|
+
const nextArtifactTypes = artifactType
|
|
71
|
+
? [...filterStore.availableArtifactTypes, artifactType]
|
|
72
|
+
: [...filterStore.availableArtifactTypes];
|
|
73
|
+
const nextProducers = producer
|
|
74
|
+
? [...filterStore.availableProducers, producer]
|
|
75
|
+
: [...filterStore.availableProducers];
|
|
76
|
+
const nextTags = tags.length > 0 ? [...filterStore.availableTags, ...tags] : [...filterStore.availableTags];
|
|
77
|
+
const nextVisibility = visibilityKind
|
|
78
|
+
? [...filterStore.availableVisibility, visibilityKind]
|
|
79
|
+
: [...filterStore.availableVisibility];
|
|
80
|
+
|
|
81
|
+
filterStore.updateAvailableFacets({
|
|
82
|
+
artifactTypes: nextArtifactTypes,
|
|
83
|
+
producers: nextProducers,
|
|
84
|
+
tags: nextTags,
|
|
85
|
+
visibilities: nextVisibility,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const baseSummary =
|
|
89
|
+
filterStore.summary ?? {
|
|
90
|
+
total: 0,
|
|
91
|
+
by_type: {} as Record<string, number>,
|
|
92
|
+
by_producer: {} as Record<string, number>,
|
|
93
|
+
by_visibility: {} as Record<string, number>,
|
|
94
|
+
tag_counts: {} as Record<string, number>,
|
|
95
|
+
earliest_created_at: null as string | null,
|
|
96
|
+
latest_created_at: null as string | null,
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const timestampIso =
|
|
100
|
+
(typeof data.timestamp === 'string' ? data.timestamp : undefined) ?? new Date().toISOString();
|
|
101
|
+
|
|
102
|
+
const updatedSummary = {
|
|
103
|
+
total: baseSummary.total + 1,
|
|
104
|
+
by_type: { ...baseSummary.by_type },
|
|
105
|
+
by_producer: { ...baseSummary.by_producer },
|
|
106
|
+
by_visibility: { ...baseSummary.by_visibility },
|
|
107
|
+
tag_counts: { ...baseSummary.tag_counts },
|
|
108
|
+
earliest_created_at:
|
|
109
|
+
baseSummary.earliest_created_at === null || timestampIso < baseSummary.earliest_created_at
|
|
110
|
+
? timestampIso
|
|
111
|
+
: baseSummary.earliest_created_at,
|
|
112
|
+
latest_created_at:
|
|
113
|
+
baseSummary.latest_created_at === null || timestampIso > baseSummary.latest_created_at
|
|
114
|
+
? timestampIso
|
|
115
|
+
: baseSummary.latest_created_at,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
if (artifactType) {
|
|
119
|
+
updatedSummary.by_type[artifactType] = (updatedSummary.by_type[artifactType] || 0) + 1;
|
|
120
|
+
}
|
|
121
|
+
if (producer) {
|
|
122
|
+
updatedSummary.by_producer[producer] = (updatedSummary.by_producer[producer] || 0) + 1;
|
|
123
|
+
}
|
|
124
|
+
if (visibilityKind) {
|
|
125
|
+
updatedSummary.by_visibility[visibilityKind] = (updatedSummary.by_visibility[visibilityKind] || 0) + 1;
|
|
126
|
+
}
|
|
127
|
+
tags.forEach((tag: string) => {
|
|
128
|
+
updatedSummary.tag_counts[tag] = (updatedSummary.tag_counts[tag] || 0) + 1;
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
filterStore.setSummary(updatedSummary);
|
|
132
|
+
|
|
133
|
+
if (typeof data.correlation_id === 'string' && data.correlation_id.length > 0) {
|
|
134
|
+
const timestampMs =
|
|
135
|
+
typeof data.timestamp === 'string' ? new Date(data.timestamp).getTime() : Date.now();
|
|
136
|
+
const existing = filterStore.availableCorrelationIds.find(
|
|
137
|
+
(item) => item.correlation_id === data.correlation_id
|
|
138
|
+
);
|
|
139
|
+
const updatedRecord = existing
|
|
140
|
+
? {
|
|
141
|
+
...existing,
|
|
142
|
+
artifact_count: existing.artifact_count + 1,
|
|
143
|
+
first_seen: Math.min(existing.first_seen, timestampMs),
|
|
144
|
+
}
|
|
145
|
+
: {
|
|
146
|
+
correlation_id: data.correlation_id,
|
|
147
|
+
first_seen: timestampMs,
|
|
148
|
+
artifact_count: 1,
|
|
149
|
+
run_count: 0,
|
|
150
|
+
};
|
|
151
|
+
const nextMetadata = [
|
|
152
|
+
...filterStore.availableCorrelationIds.filter((item) => item.correlation_id !== data.correlation_id),
|
|
153
|
+
updatedRecord,
|
|
154
|
+
];
|
|
155
|
+
filterStore.updateAvailableCorrelationIds(nextMetadata);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
54
159
|
private setupEventHandlers(): void {
|
|
55
160
|
// Handler for agent_activated: create/update agent in graph AND create Run
|
|
56
161
|
this.on('agent_activated', (data) => {
|
|
@@ -117,11 +222,17 @@ export class WebSocketClient {
|
|
|
117
222
|
|
|
118
223
|
if (existingMessage) {
|
|
119
224
|
// Update existing streaming message with final data
|
|
225
|
+
const tags = Array.isArray(data.tags) ? data.tags : [];
|
|
226
|
+
const visibilityKind = data.visibility?.kind || data.visibility_kind || 'Unknown';
|
|
120
227
|
const finalMessage = {
|
|
121
228
|
...existingMessage,
|
|
122
229
|
id: data.artifact_id, // Replace temp ID with real artifact ID
|
|
123
230
|
type: data.artifact_type,
|
|
124
231
|
payload: data.payload,
|
|
232
|
+
tags,
|
|
233
|
+
visibilityKind,
|
|
234
|
+
partitionKey: data.partition_key ?? null,
|
|
235
|
+
version: data.version ?? 1,
|
|
125
236
|
isStreaming: false, // Streaming complete
|
|
126
237
|
streamingText: '', // Clear streaming text
|
|
127
238
|
};
|
|
@@ -130,6 +241,8 @@ export class WebSocketClient {
|
|
|
130
241
|
useGraphStore.getState().finalizeStreamingMessage(streamingMessageId, finalMessage);
|
|
131
242
|
} else {
|
|
132
243
|
// No streaming message - create new message directly
|
|
244
|
+
const tags = Array.isArray(data.tags) ? data.tags : [];
|
|
245
|
+
const visibilityKind = data.visibility?.kind || data.visibility_kind || 'Unknown';
|
|
133
246
|
const message = {
|
|
134
247
|
id: data.artifact_id,
|
|
135
248
|
type: data.artifact_type,
|
|
@@ -137,6 +250,10 @@ export class WebSocketClient {
|
|
|
137
250
|
timestamp: data.timestamp ? new Date(data.timestamp).getTime() : Date.now(),
|
|
138
251
|
correlationId: data.correlation_id || '',
|
|
139
252
|
producedBy: data.produced_by,
|
|
253
|
+
tags,
|
|
254
|
+
visibilityKind,
|
|
255
|
+
partitionKey: data.partition_key ?? null,
|
|
256
|
+
version: data.version ?? 1,
|
|
140
257
|
isStreaming: false,
|
|
141
258
|
};
|
|
142
259
|
this.store.addMessage(message);
|
|
@@ -206,6 +323,16 @@ export class WebSocketClient {
|
|
|
206
323
|
}
|
|
207
324
|
}
|
|
208
325
|
}
|
|
326
|
+
|
|
327
|
+
this.updateFilterStateFromPublishedMessage(data);
|
|
328
|
+
|
|
329
|
+
// Ensure blackboard graph reflects the newly published artifact immediately
|
|
330
|
+
const mode = useUIStore.getState().mode;
|
|
331
|
+
if (mode === 'blackboard') {
|
|
332
|
+
useGraphStore.getState().generateBlackboardViewGraph();
|
|
333
|
+
} else if (mode === 'agent') {
|
|
334
|
+
useGraphStore.getState().generateAgentViewGraph();
|
|
335
|
+
}
|
|
209
336
|
});
|
|
210
337
|
|
|
211
338
|
// Handler for streaming_output: update live output (Phase 6)
|
|
@@ -255,6 +382,8 @@ export class WebSocketClient {
|
|
|
255
382
|
timestamp: data.timestamp ? new Date(data.timestamp).getTime() : Date.now(),
|
|
256
383
|
correlationId: data.correlation_id || '',
|
|
257
384
|
producedBy: data.agent_name,
|
|
385
|
+
tags: [],
|
|
386
|
+
visibilityKind: 'Unknown',
|
|
258
387
|
isStreaming: true,
|
|
259
388
|
streamingText: data.content,
|
|
260
389
|
};
|