flock-core 0.5.3__py3-none-any.whl → 0.5.5__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 (44) hide show
  1. flock/agent.py +20 -1
  2. flock/artifact_collector.py +2 -3
  3. flock/batch_accumulator.py +4 -4
  4. flock/components.py +32 -0
  5. flock/correlation_engine.py +9 -4
  6. flock/dashboard/collector.py +4 -0
  7. flock/dashboard/events.py +74 -0
  8. flock/dashboard/graph_builder.py +272 -0
  9. flock/dashboard/models/graph.py +3 -1
  10. flock/dashboard/service.py +363 -14
  11. flock/dashboard/static_v2/assets/index-DFRnI_mt.js +1 -1
  12. flock/dashboard/static_v2/index.html +3 -3
  13. flock/engines/dspy_engine.py +41 -3
  14. flock/engines/examples/__init__.py +6 -0
  15. flock/engines/examples/simple_batch_engine.py +61 -0
  16. flock/frontend/README.md +4 -4
  17. flock/frontend/docs/DESIGN_SYSTEM.md +1 -1
  18. flock/frontend/package-lock.json +2 -2
  19. flock/frontend/package.json +2 -2
  20. flock/frontend/src/components/controls/PublishControl.test.tsx +11 -11
  21. flock/frontend/src/components/controls/PublishControl.tsx +1 -1
  22. flock/frontend/src/components/graph/AgentNode.tsx +4 -0
  23. flock/frontend/src/components/graph/GraphCanvas.tsx +4 -0
  24. flock/frontend/src/components/graph/LogicOperationsDisplay.tsx +463 -0
  25. flock/frontend/src/components/graph/PendingBatchEdge.tsx +141 -0
  26. flock/frontend/src/components/graph/PendingJoinEdge.tsx +144 -0
  27. flock/frontend/src/components/settings/SettingsPanel.css +1 -1
  28. flock/frontend/src/components/settings/ThemeSelector.tsx +2 -2
  29. flock/frontend/src/services/graphService.ts +3 -1
  30. flock/frontend/src/services/indexeddb.ts +1 -1
  31. flock/frontend/src/services/websocket.ts +99 -1
  32. flock/frontend/src/store/graphStore.test.ts +2 -1
  33. flock/frontend/src/store/graphStore.ts +36 -5
  34. flock/frontend/src/styles/variables.css +1 -1
  35. flock/frontend/src/types/graph.ts +86 -0
  36. flock/orchestrator.py +268 -13
  37. flock/patches/__init__.py +1 -0
  38. flock/patches/dspy_streaming_patch.py +1 -0
  39. flock/runtime.py +3 -0
  40. {flock_core-0.5.3.dist-info → flock_core-0.5.5.dist-info}/METADATA +11 -1
  41. {flock_core-0.5.3.dist-info → flock_core-0.5.5.dist-info}/RECORD +44 -39
  42. {flock_core-0.5.3.dist-info → flock_core-0.5.5.dist-info}/WHEEL +0 -0
  43. {flock_core-0.5.3.dist-info → flock_core-0.5.5.dist-info}/entry_points.txt +0 -0
  44. {flock_core-0.5.3.dist-info → flock_core-0.5.5.dist-info}/licenses/LICENSE +0 -0
@@ -4,10 +4,10 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>🦆🐓 Flock 🐤🐧</title>
7
- <script type="module" crossorigin src="/assets/index-DFRnI_mt.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-fPLNdmp1.css">
7
+ <script type="module" crossorigin src="/assets/index-DFRnI_mt.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-fPLNdmp1.css">
9
9
  </head>
10
10
  <body>
11
- <div id="root"></div>
11
+ <div id="root"></div>
12
12
  </body>
13
13
  </html>
@@ -153,6 +153,19 @@ class DSPyEngine(EngineComponent):
153
153
  )
154
154
 
155
155
  async def evaluate(self, agent, ctx, inputs: EvalInputs) -> EvalResult: # type: ignore[override]
156
+ return await self._evaluate_internal(agent, ctx, inputs, batched=False)
157
+
158
+ async def evaluate_batch(self, agent, ctx, inputs: EvalInputs) -> EvalResult: # type: ignore[override]
159
+ return await self._evaluate_internal(agent, ctx, inputs, batched=True)
160
+
161
+ async def _evaluate_internal(
162
+ self,
163
+ agent,
164
+ ctx,
165
+ inputs: EvalInputs,
166
+ *,
167
+ batched: bool,
168
+ ) -> EvalResult:
156
169
  if not inputs.artifacts:
157
170
  return EvalResult(artifacts=[], state=dict(inputs.state))
158
171
 
@@ -169,7 +182,13 @@ class DSPyEngine(EngineComponent):
169
182
 
170
183
  primary_artifact = self._select_primary_artifact(inputs.artifacts)
171
184
  input_model = self._resolve_input_model(primary_artifact)
172
- validated_input = self._validate_input_payload(input_model, primary_artifact.payload)
185
+ if batched:
186
+ validated_input = [
187
+ self._validate_input_payload(input_model, artifact.payload)
188
+ for artifact in inputs.artifacts
189
+ ]
190
+ else:
191
+ validated_input = self._validate_input_payload(input_model, primary_artifact.payload)
173
192
  output_model = self._resolve_output_model(agent)
174
193
 
175
194
  # Fetch conversation context from blackboard
@@ -183,6 +202,7 @@ class DSPyEngine(EngineComponent):
183
202
  input_schema=input_model,
184
203
  output_schema=output_model,
185
204
  has_context=has_context,
205
+ batched=batched,
186
206
  )
187
207
 
188
208
  sys_desc = self._system_description(self.instructions or agent.description)
@@ -193,7 +213,11 @@ class DSPyEngine(EngineComponent):
193
213
  pre_generated_artifact_id = uuid4()
194
214
 
195
215
  # Build execution payload with context
196
- if has_context:
216
+ if batched:
217
+ execution_payload = {"input": validated_input}
218
+ if has_context:
219
+ execution_payload["context"] = context_history
220
+ elif has_context:
197
221
  execution_payload = {
198
222
  "input": validated_input,
199
223
  "context": context_history,
@@ -383,6 +407,7 @@ class DSPyEngine(EngineComponent):
383
407
  input_schema: type[BaseModel] | None,
384
408
  output_schema: type[BaseModel] | None,
385
409
  has_context: bool = False,
410
+ batched: bool = False,
386
411
  ) -> Any:
387
412
  """Prepare DSPy signature, optionally including context field."""
388
413
  fields = {
@@ -398,7 +423,15 @@ class DSPyEngine(EngineComponent):
398
423
  ),
399
424
  )
400
425
 
401
- fields["input"] = (input_schema or dict, dspy_mod.InputField())
426
+ if batched:
427
+ if input_schema is not None:
428
+ input_type = list[input_schema]
429
+ else:
430
+ input_type = list[dict[str, Any]]
431
+ else:
432
+ input_type = input_schema or dict
433
+
434
+ fields["input"] = (input_type, dspy_mod.InputField())
402
435
  fields["output"] = (output_schema or dict, dspy_mod.OutputField())
403
436
 
404
437
  signature = dspy_mod.Signature(fields)
@@ -406,6 +439,11 @@ class DSPyEngine(EngineComponent):
406
439
  instruction = description or "Produce a valid output that matches the 'output' schema."
407
440
  if has_context:
408
441
  instruction += " Consider the conversation context provided to inform your response."
442
+ if batched:
443
+ instruction += (
444
+ " The 'input' field will contain a list of items representing the batch; "
445
+ "process the entire collection coherently."
446
+ )
409
447
  instruction += " Return only JSON."
410
448
 
411
449
  return signature.with_instructions(instruction)
@@ -0,0 +1,6 @@
1
+ """Reference engine implementations."""
2
+
3
+ from .simple_batch_engine import SimpleBatchEngine
4
+
5
+
6
+ __all__ = ["SimpleBatchEngine"]
@@ -0,0 +1,61 @@
1
+ """Reference batch-aware engine used in tutorials and tests."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+ from flock.components import EngineComponent
8
+ from flock.registry import flock_type
9
+ from flock.runtime import EvalInputs, EvalResult
10
+
11
+
12
+ @flock_type(name="BatchItem")
13
+ class BatchItem(BaseModel):
14
+ """Input payload used by reference tests and tutorials."""
15
+
16
+ value: int = Field(description="Numeric value contributed by the artifact")
17
+
18
+
19
+ @flock_type(name="BatchSummary")
20
+ class BatchSummary(BaseModel):
21
+ """Output payload describing the batch that was processed."""
22
+
23
+ batch_size: int = Field(description="Number of items included in this evaluation")
24
+ values: list[int] = Field(description="Original values processed", default_factory=list)
25
+
26
+
27
+ class SimpleBatchEngine(EngineComponent):
28
+ """Example engine that processes items individually or in batches.
29
+
30
+ - ``evaluate`` is used when the agent is invoked directly without BatchSpec.
31
+ - ``evaluate_batch`` is triggered when BatchSpec flushes accumulated artifacts.
32
+
33
+ The engine simply annotates each item with the current batch size so tests can
34
+ verify that all artifacts were processed together.
35
+ """
36
+
37
+ async def evaluate(self, agent, ctx, inputs: EvalInputs) -> EvalResult:
38
+ item = inputs.first_as(BatchItem)
39
+ if item is None:
40
+ return EvalResult.empty()
41
+
42
+ annotated = BatchSummary(batch_size=1, values=[item.value])
43
+ state = dict(inputs.state)
44
+ state.setdefault("batch_size", annotated.batch_size)
45
+ state.setdefault("processed_values", list(annotated.values))
46
+
47
+ return EvalResult.from_object(annotated, agent=agent, state=state)
48
+
49
+ async def evaluate_batch(self, agent, ctx, inputs: EvalInputs) -> EvalResult:
50
+ items = inputs.all_as(BatchItem)
51
+ if not items:
52
+ return EvalResult.empty()
53
+
54
+ batch_size = len(items)
55
+ summary = BatchSummary(batch_size=batch_size, values=[item.value for item in items])
56
+
57
+ state = dict(inputs.state)
58
+ state["batch_size"] = summary.batch_size
59
+ state["processed_values"] = list(summary.values)
60
+
61
+ return EvalResult.from_object(summary, agent=agent, state=state)
flock/frontend/README.md CHANGED
@@ -1,10 +1,10 @@
1
- # Flock Flow Dashboard
1
+ # Flock Dashboard
2
2
 
3
- A real-time visualization dashboard for monitoring and controlling Flock Flow agent orchestration systems. Built with modern web technologies to provide an intuitive, high-performance interface for observing multi-agent workflows.
3
+ A real-time visualization dashboard for monitoring and controlling Flock agent orchestration systems. Built with modern web technologies to provide an intuitive, high-performance interface for observing multi-agent workflows.
4
4
 
5
5
  ## Overview
6
6
 
7
- The Flock Flow Dashboard provides real-time visibility into your agent orchestration system through an interactive graph-based interface. Watch agents activate, messages flow, and data transform in real-time as your multi-agent system operates.
7
+ The Flock Dashboard provides real-time visibility into your agent orchestration system through an interactive graph-based interface. Watch agents activate, messages flow, and data transform in real-time as your multi-agent system operates.
8
8
 
9
9
  The dashboard offers two complementary visualization modes:
10
10
  - **Agent View**: Shows agents as nodes with message flows as edges - perfect for understanding agent communication patterns
@@ -149,7 +149,7 @@ Launch the module via the context menu (or `Add Module → Historical Blackboard
149
149
 
150
150
  - **Node.js**: Version 18 or higher
151
151
  - **Package Manager**: npm (included with Node.js) or yarn
152
- - **Flock Flow Backend**: Running orchestrator instance (typically on port 8344)
152
+ - **Flock Backend**: Running orchestrator instance (typically on port 8344)
153
153
 
154
154
  ### Installation
155
155
 
@@ -1,4 +1,4 @@
1
- # Flock Flow Dashboard Design System
1
+ # Flock Dashboard Design System
2
2
 
3
3
  **Version:** 1.0.0
4
4
  **Last Updated:** October 2025
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "flock-ui",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "flock-ui",
9
- "version": "0.1.7",
9
+ "version": "0.1.8",
10
10
  "license": "ISC",
11
11
  "dependencies": {
12
12
  "@types/dagre": "^0.7.53",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "flock-ui",
3
- "version": "0.1.7",
4
- "description": "Flock Flow Real-Time Dashboard Frontend",
3
+ "version": "0.1.8",
4
+ "description": "Flock Real-Time Dashboard Frontend",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
@@ -398,7 +398,7 @@ describe('PublishControl', () => {
398
398
  });
399
399
 
400
400
  // Auto-filter checkbox tests
401
- it('should render auto-set filter checkbox checked by default', async () => {
401
+ it('should render auto-set filter checkbox unchecked by default', async () => {
402
402
  mockFetch.mockResolvedValueOnce({
403
403
  ok: true,
404
404
  json: async () => ({ artifact_types: mockArtifactTypes }),
@@ -412,7 +412,7 @@ describe('PublishControl', () => {
412
412
 
413
413
  const checkbox = screen.getByLabelText(/set filter to correlation id/i) as HTMLInputElement;
414
414
  expect(checkbox).toBeInTheDocument();
415
- expect(checkbox.checked).toBe(true);
415
+ expect(checkbox.checked).toBe(false);
416
416
  });
417
417
 
418
418
  it('should set filter to correlation ID when checkbox is checked and publish succeeds', async () => {
@@ -439,7 +439,8 @@ describe('PublishControl', () => {
439
439
  const artifactTypeSelect = screen.getByLabelText(/artifact type/i);
440
440
  const checkbox = screen.getByLabelText(/set filter to correlation id/i) as HTMLInputElement;
441
441
 
442
- // Checkbox should be checked by default
442
+ // Check the checkbox to enable auto-filter
443
+ fireEvent.click(checkbox);
443
444
  expect(checkbox.checked).toBe(true);
444
445
 
445
446
  fireEvent.change(artifactTypeSelect, { target: { value: 'Idea' } });
@@ -487,8 +488,7 @@ describe('PublishControl', () => {
487
488
  const artifactTypeSelect = screen.getByLabelText(/artifact type/i);
488
489
  const checkbox = screen.getByLabelText(/set filter to correlation id/i) as HTMLInputElement;
489
490
 
490
- // Uncheck the checkbox
491
- fireEvent.click(checkbox);
491
+ // Checkbox should already be unchecked by default
492
492
  expect(checkbox.checked).toBe(false);
493
493
 
494
494
  // Clear any existing filter
@@ -529,15 +529,15 @@ describe('PublishControl', () => {
529
529
 
530
530
  const checkbox = screen.getByLabelText(/set filter to correlation id/i) as HTMLInputElement;
531
531
 
532
- // Initially checked
533
- expect(checkbox.checked).toBe(true);
534
-
535
- // Uncheck
536
- fireEvent.click(checkbox);
532
+ // Initially unchecked
537
533
  expect(checkbox.checked).toBe(false);
538
534
 
539
- // Check again
535
+ // Check
540
536
  fireEvent.click(checkbox);
541
537
  expect(checkbox.checked).toBe(true);
538
+
539
+ // Uncheck again
540
+ fireEvent.click(checkbox);
541
+ expect(checkbox.checked).toBe(false);
542
542
  });
543
543
  });
@@ -22,7 +22,7 @@ const PublishControl: React.FC = () => {
22
22
  const [errors, setErrors] = useState<ValidationErrors>({});
23
23
  const [successMessage, setSuccessMessage] = useState('');
24
24
  const [errorMessage, setErrorMessage] = useState('');
25
- const [autoSetFilter, setAutoSetFilter] = useState(true); // Default: auto-set filter to correlation ID
25
+ const [autoSetFilter, setAutoSetFilter] = useState(false); // Default: unchecked (user can opt-in to auto-filter)
26
26
 
27
27
  const setShowControls = useSettingsStore((state) => state.setShowControls);
28
28
 
@@ -2,6 +2,7 @@ import { memo, useState, useEffect, useRef } from 'react';
2
2
  import { NodeProps, Handle, Position } from '@xyflow/react';
3
3
  import { useUIStore } from '../../store/uiStore';
4
4
  import { useSettingsStore } from '../../store/settingsStore';
5
+ import LogicOperationsDisplay from './LogicOperationsDisplay';
5
6
 
6
7
  // UI Optimization Migration (Phase 4.1 - Spec 002): Backend GraphNode.data is Record<string, any>
7
8
  // Agent-specific properties populated by backend snapshot
@@ -16,6 +17,7 @@ const AgentNode = memo(({ data, selected }: NodeProps) => {
16
17
  const receivedByType = nodeData.receivedByType || {};
17
18
  const sentByType = nodeData.sentByType || {};
18
19
  const streamingTokens = nodeData.streamingTokens || [];
20
+ const logicOperations = nodeData.logicOperations || []; // Phase 1.4: Logic operations state
19
21
 
20
22
  // Merge known types with actual counts - show all types even with 0 count
21
23
  // Start with actual counts, then add known types that haven't happened yet
@@ -307,6 +309,8 @@ const AgentNode = memo(({ data, selected }: NodeProps) => {
307
309
  </div>
308
310
  </div>
309
311
  )}
312
+ {/* Phase 1.4: Logic Operations Display (JoinSpec/BatchSpec waiting states) */}
313
+ <LogicOperationsDisplay logicOperations={logicOperations} compactNodeView={compactNodeView} />
310
314
  </div>
311
315
  )}
312
316
  {compactNodeView && (
@@ -15,6 +15,8 @@ import AgentNode from './AgentNode';
15
15
  import MessageNode from './MessageNode';
16
16
  import MessageFlowEdge from './MessageFlowEdge';
17
17
  import TransformEdge from './TransformEdge';
18
+ import PendingJoinEdge from './PendingJoinEdge';
19
+ import PendingBatchEdge from './PendingBatchEdge';
18
20
  import MiniMap from './MiniMap';
19
21
  import { useGraphStore } from '../../store/graphStore';
20
22
  import { useFilterStore } from '../../store/filterStore';
@@ -78,6 +80,8 @@ const GraphCanvas: React.FC = () => {
78
80
  () => ({
79
81
  message_flow: MessageFlowEdge,
80
82
  transformation: TransformEdge,
83
+ pending_join: PendingJoinEdge, // Phase 1.5: Pending edges for JoinSpec correlation groups
84
+ pending_batch: PendingBatchEdge, // Phase 1.5: Pending edges for BatchSpec accumulation
81
85
  }),
82
86
  []
83
87
  );