flock-core 0.5.4__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.

@@ -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
3
  "version": "0.1.8",
4
- "description": "Flock Flow Real-Time Dashboard Frontend",
4
+ "description": "Flock Real-Time Dashboard Frontend",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
@@ -1,6 +1,6 @@
1
1
  /* ========================================
2
2
  Settings Panel Styles
3
- Using Flock Flow Design System
3
+ Using Flock Design System
4
4
  ======================================== */
5
5
 
6
6
  .settings-panel {
@@ -150,7 +150,7 @@ const ThemeSelector: React.FC = () => {
150
150
  justifyContent: 'space-between',
151
151
  }}>
152
152
  <span style={{ color: 'var(--color-text-primary)' }}>
153
- {currentTheme === 'default' ? 'Default (Flock Flow)' : currentTheme}
153
+ {currentTheme === 'default' ? 'Default (Flock)' : currentTheme}
154
154
  </span>
155
155
  {currentTheme !== 'default' && (
156
156
  <button
@@ -191,7 +191,7 @@ const ThemeSelector: React.FC = () => {
191
191
  transition: 'var(--transition-all)',
192
192
  }}
193
193
  >
194
- Default (Flock Flow)
194
+ Default (Flock)
195
195
  </button>
196
196
  </div>
197
197
  </div>
@@ -1,5 +1,5 @@
1
1
  /**
2
- * IndexedDB Persistence Service for Flock Flow Dashboard
2
+ * IndexedDB Persistence Service for Flock Dashboard
3
3
  *
4
4
  * Provides persistent storage for dashboard data with LRU eviction strategy.
5
5
  * Implements separate layout storage for Agent View and Blackboard View.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Flock Flow Dashboard Design System
2
+ * Flock Dashboard Design System
3
3
  * Generated from frontend/docs/DESIGN_SYSTEM.md
4
4
  * Version: 1.0.0
5
5
  */
flock/orchestrator.py CHANGED
@@ -8,7 +8,7 @@ import os
8
8
  from asyncio import Task
9
9
  from collections.abc import AsyncGenerator, Iterable, Mapping, Sequence
10
10
  from contextlib import asynccontextmanager
11
- from datetime import datetime, timezone
11
+ from datetime import datetime, timedelta, timezone
12
12
  from pathlib import Path
13
13
  from typing import TYPE_CHECKING, Any
14
14
  from uuid import uuid4
@@ -135,8 +135,14 @@ class Flock(metaclass=AutoTracedMeta):
135
135
  self._artifact_collector = ArtifactCollector()
136
136
  # JoinSpec logic: Correlation engine for correlated AND gates
137
137
  self._correlation_engine = CorrelationEngine()
138
+ # Background task for checking correlation expiry (time-based JoinSpec)
139
+ self._correlation_cleanup_task: Task[Any] | None = None
140
+ self._correlation_cleanup_interval: float = 0.1 # Check every 100ms
138
141
  # BatchSpec logic: Batch accumulator for size/timeout batching
139
142
  self._batch_engine = BatchEngine()
143
+ # Background task for checking batch timeouts
144
+ self._batch_timeout_task: Task[Any] | None = None
145
+ self._batch_timeout_interval: float = 0.1 # Check every 100ms
140
146
  # Phase 1.2: WebSocket manager for real-time dashboard events (set by serve())
141
147
  self._websocket_manager: Any = None
142
148
  # Unified tracing support
@@ -473,6 +479,33 @@ class Flock(metaclass=AutoTracedMeta):
473
479
  await asyncio.sleep(0.01)
474
480
  pending = {task for task in self._tasks if not task.done()}
475
481
  self._tasks = pending
482
+
483
+ # Determine whether any deferred work (timeouts/cleanup) is still pending.
484
+ pending_batches = any(
485
+ accumulator.artifacts for accumulator in self._batch_engine.batches.values()
486
+ )
487
+ pending_correlations = any(
488
+ groups and any(group.waiting_artifacts for group in groups.values())
489
+ for groups in self._correlation_engine.correlation_groups.values()
490
+ )
491
+
492
+ # Ensure watchdog loops remain active while pending work exists.
493
+ if pending_batches and (
494
+ self._batch_timeout_task is None or self._batch_timeout_task.done()
495
+ ):
496
+ self._batch_timeout_task = asyncio.create_task(self._batch_timeout_checker_loop())
497
+
498
+ if pending_correlations and (
499
+ self._correlation_cleanup_task is None or self._correlation_cleanup_task.done()
500
+ ):
501
+ self._correlation_cleanup_task = asyncio.create_task(self._correlation_cleanup_loop())
502
+
503
+ # If deferred work is still outstanding, consider the orchestrator quiescent for
504
+ # now but leave watchdog tasks running to finish the job.
505
+ if pending_batches or pending_correlations:
506
+ self._agent_iteration_count.clear()
507
+ return
508
+
476
509
  # T068: Reset circuit breaker counters when idle
477
510
  self._agent_iteration_count.clear()
478
511
 
@@ -548,6 +581,22 @@ class Flock(metaclass=AutoTracedMeta):
548
581
 
549
582
  async def shutdown(self) -> None:
550
583
  """Shutdown orchestrator and clean up resources."""
584
+ # Cancel correlation cleanup task if running
585
+ if self._correlation_cleanup_task and not self._correlation_cleanup_task.done():
586
+ self._correlation_cleanup_task.cancel()
587
+ try:
588
+ await self._correlation_cleanup_task
589
+ except asyncio.CancelledError:
590
+ pass
591
+
592
+ # Cancel batch timeout checker if running
593
+ if self._batch_timeout_task and not self._batch_timeout_task.done():
594
+ self._batch_timeout_task.cancel()
595
+ try:
596
+ await self._batch_timeout_task
597
+ except asyncio.CancelledError:
598
+ pass
599
+
551
600
  if self._mcp_manager is not None:
552
601
  await self._mcp_manager.cleanup_all()
553
602
  self._mcp_manager = None
@@ -909,6 +958,15 @@ class Flock(metaclass=AutoTracedMeta):
909
958
  subscription_index=subscription_index,
910
959
  )
911
960
 
961
+ # Start correlation cleanup task if time-based window and not running
962
+ if (
963
+ isinstance(subscription.join.within, timedelta)
964
+ and self._correlation_cleanup_task is None
965
+ ):
966
+ self._correlation_cleanup_task = asyncio.create_task(
967
+ self._correlation_cleanup_loop()
968
+ )
969
+
912
970
  if completed_group is None:
913
971
  # Still waiting for correlation to complete
914
972
  # Phase 1.2: Emit real-time correlation update event
@@ -948,6 +1006,12 @@ class Flock(metaclass=AutoTracedMeta):
948
1006
  subscription=subscription,
949
1007
  subscription_index=subscription_index,
950
1008
  )
1009
+
1010
+ # Start timeout checker if this batch has a timeout and checker not running
1011
+ if subscription.batch.timeout and self._batch_timeout_task is None:
1012
+ self._batch_timeout_task = asyncio.create_task(
1013
+ self._batch_timeout_checker_loop()
1014
+ )
951
1015
  else:
952
1016
  # Single type subscription: Add each artifact individually
953
1017
  should_flush = False
@@ -958,6 +1022,12 @@ class Flock(metaclass=AutoTracedMeta):
958
1022
  subscription_index=subscription_index,
959
1023
  )
960
1024
 
1025
+ # Start timeout checker if this batch has a timeout and checker not running
1026
+ if subscription.batch.timeout and self._batch_timeout_task is None:
1027
+ self._batch_timeout_task = asyncio.create_task(
1028
+ self._batch_timeout_checker_loop()
1029
+ )
1030
+
961
1031
  if should_flush:
962
1032
  # Size threshold reached! Flush batch now
963
1033
  break
@@ -994,10 +1064,14 @@ class Flock(metaclass=AutoTracedMeta):
994
1064
  self._mark_processed(collected_artifact, agent)
995
1065
 
996
1066
  # Schedule agent with ALL artifacts (batched, correlated, or AND gate complete)
997
- self._schedule_task(agent, artifacts)
1067
+ # NEW: Mark as batch execution if flushed from BatchSpec
1068
+ is_batch_execution = subscription.batch is not None
1069
+ self._schedule_task(agent, artifacts, is_batch=is_batch_execution)
998
1070
 
999
- def _schedule_task(self, agent: Agent, artifacts: list[Artifact]) -> None:
1000
- task = asyncio.create_task(self._run_agent_task(agent, artifacts))
1071
+ def _schedule_task(
1072
+ self, agent: Agent, artifacts: list[Artifact], is_batch: bool = False
1073
+ ) -> None:
1074
+ task = asyncio.create_task(self._run_agent_task(agent, artifacts, is_batch=is_batch))
1001
1075
  self._tasks.add(task)
1002
1076
  task.add_done_callback(self._tasks.discard)
1003
1077
 
@@ -1012,14 +1086,17 @@ class Flock(metaclass=AutoTracedMeta):
1012
1086
  key = (str(artifact.id), agent.name)
1013
1087
  return key in self._processed
1014
1088
 
1015
- async def _run_agent_task(self, agent: Agent, artifacts: list[Artifact]) -> None:
1089
+ async def _run_agent_task(
1090
+ self, agent: Agent, artifacts: list[Artifact], is_batch: bool = False
1091
+ ) -> None:
1016
1092
  correlation_id = artifacts[0].correlation_id if artifacts else uuid4()
1017
1093
 
1018
1094
  ctx = Context(
1019
1095
  board=BoardHandle(self),
1020
1096
  orchestrator=self,
1021
1097
  task_id=str(uuid4()),
1022
- correlation_id=correlation_id, # NEW!
1098
+ correlation_id=correlation_id,
1099
+ is_batch=is_batch, # NEW!
1023
1100
  )
1024
1101
  self._record_agent_run(agent)
1025
1102
  await agent.execute(ctx, artifacts)
@@ -1154,11 +1231,63 @@ class Flock(metaclass=AutoTracedMeta):
1154
1231
 
1155
1232
  # Batch Helpers --------------------------------------------------------
1156
1233
 
1234
+ async def _correlation_cleanup_loop(self) -> None:
1235
+ """Background task that periodically cleans up expired correlation groups.
1236
+
1237
+ Runs continuously until all correlation groups are cleared or orchestrator shuts down.
1238
+ Checks every 100ms for time-based expired correlations and discards them.
1239
+ """
1240
+ try:
1241
+ while True:
1242
+ await asyncio.sleep(self._correlation_cleanup_interval)
1243
+ self._cleanup_expired_correlations()
1244
+
1245
+ # Stop if no correlation groups remain
1246
+ if not self._correlation_engine.correlation_groups:
1247
+ self._correlation_cleanup_task = None
1248
+ break
1249
+ except asyncio.CancelledError:
1250
+ # Clean shutdown
1251
+ self._correlation_cleanup_task = None
1252
+ raise
1253
+
1254
+ def _cleanup_expired_correlations(self) -> None:
1255
+ """Clean up all expired correlation groups across all subscriptions.
1256
+
1257
+ Called periodically by background task to enforce time-based correlation windows.
1258
+ Discards incomplete correlations that have exceeded their time window.
1259
+ """
1260
+ # Get all active subscription keys
1261
+ for agent_name, subscription_index in list(
1262
+ self._correlation_engine.correlation_groups.keys()
1263
+ ):
1264
+ self._correlation_engine.cleanup_expired(agent_name, subscription_index)
1265
+
1266
+ async def _batch_timeout_checker_loop(self) -> None:
1267
+ """Background task that periodically checks for batch timeouts.
1268
+
1269
+ Runs continuously until all batches are cleared or orchestrator shuts down.
1270
+ Checks every 100ms for expired batches and flushes them.
1271
+ """
1272
+ try:
1273
+ while True:
1274
+ await asyncio.sleep(self._batch_timeout_interval)
1275
+ await self._check_batch_timeouts()
1276
+
1277
+ # Stop if no batches remain
1278
+ if not self._batch_engine.batches:
1279
+ self._batch_timeout_task = None
1280
+ break
1281
+ except asyncio.CancelledError:
1282
+ # Clean shutdown
1283
+ self._batch_timeout_task = None
1284
+ raise
1285
+
1157
1286
  async def _check_batch_timeouts(self) -> None:
1158
1287
  """Check all batches for timeout expiry and flush expired batches.
1159
1288
 
1160
- This method is called periodically or manually (in tests) to enforce
1161
- timeout-based batching.
1289
+ This method is called periodically by the background timeout checker
1290
+ or manually (in tests) to enforce timeout-based batching.
1162
1291
  """
1163
1292
  expired_batches = self._batch_engine.check_timeouts()
1164
1293
 
@@ -1174,8 +1303,8 @@ class Flock(metaclass=AutoTracedMeta):
1174
1303
  if agent is None:
1175
1304
  continue
1176
1305
 
1177
- # Schedule agent with batched artifacts
1178
- self._schedule_task(agent, artifacts)
1306
+ # Schedule agent with batched artifacts (timeout flush)
1307
+ self._schedule_task(agent, artifacts, is_batch=True)
1179
1308
 
1180
1309
  async def _flush_all_batches(self) -> None:
1181
1310
  """Flush all partial batches (for shutdown - ensures zero data loss)."""
@@ -1187,8 +1316,8 @@ class Flock(metaclass=AutoTracedMeta):
1187
1316
  if agent is None:
1188
1317
  continue
1189
1318
 
1190
- # Schedule agent with partial batch
1191
- self._schedule_task(agent, artifacts)
1319
+ # Schedule agent with partial batch (shutdown flush)
1320
+ self._schedule_task(agent, artifacts, is_batch=True)
1192
1321
 
1193
1322
  # Wait for all scheduled tasks to complete
1194
1323
  await self.run_until_idle()
flock/runtime.py CHANGED
@@ -250,6 +250,9 @@ class Context(BaseModel):
250
250
  correlation_id: UUID | None = None # NEW!
251
251
  task_id: str
252
252
  state: dict[str, Any] = Field(default_factory=dict)
253
+ is_batch: bool = Field(
254
+ default=False, description="True if this execution is processing a BatchSpec accumulation"
255
+ )
253
256
 
254
257
  def get_variable(self, key: str, default: Any = None) -> Any:
255
258
  return self.state.get(key, default)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flock-core
3
- Version: 0.5.4
3
+ Version: 0.5.5
4
4
  Summary: Flock: A declrative framework for building and orchestrating AI agents.
5
5
  Author-email: Andre Ratzenberger <andre.ratzenberger@whiteduck.de>
6
6
  License: MIT
@@ -57,6 +57,8 @@ Flock is a production-focused framework for orchestrating AI agents through **de
57
57
  **Quick links:**
58
58
  - **[Getting Started](https://whiteducksoftware.github.io/flock/getting-started/installation/)** - Installation and first steps
59
59
  - **[Tutorials](https://whiteducksoftware.github.io/flock/tutorials/)** - Step-by-step learning path
60
+ - [Custom Engines: Emoji Vibes & Batch Brews](https://whiteducksoftware.github.io/flock/tutorials/custom-engines/)
61
+ - [Custom Agent Components: Foreshadow & Hype](https://whiteducksoftware.github.io/flock/tutorials/custom-agent-components/)
60
62
  - **[User Guides](https://whiteducksoftware.github.io/flock/guides/)** - In-depth feature documentation
61
63
  - **[API Reference](https://whiteducksoftware.github.io/flock/reference/api/)** - Complete API documentation
62
64
  - **[Roadmap](https://whiteducksoftware.github.io/flock/about/roadmap/)** - What's coming in v1.0
@@ -1,15 +1,15 @@
1
1
  flock/__init__.py,sha256=fvp4ltfaAGmYliShuTY_XVIpOUN6bMXbWiBnwb1NBoM,310
2
- flock/agent.py,sha256=vk15p1bw2YeTPAWLZHe2I6c558cAkZXi5DERbIL15kg,41808
2
+ flock/agent.py,sha256=zlhrY8jWE6LK8hmOHaQWbfnX7_T_6Eg6Qb7oviujJiY,42715
3
3
  flock/artifact_collector.py,sha256=8rsg5NzmXeXKNT07TqX1_Z6aAGud2dXKzvS0jhjX3gQ,6372
4
4
  flock/artifacts.py,sha256=3vQQ1J7QxTzeQBUGaNLiyojlmBv1NfdhFC98-qj8fpU,2541
5
5
  flock/batch_accumulator.py,sha256=YcZSpdYMhm8wAGqKEF49NJ_Jl2HZX78NrJYqfyHqTuE,8003
6
6
  flock/cli.py,sha256=lPtKxEXnGtyuTh0gyG3ixEIFS4Ty6Y0xsPd6SpUTD3U,4526
7
- flock/components.py,sha256=17vhNMHKc3VUruEbSdb9YNKcDziIe0coS9jpfWBmX4o,6259
7
+ flock/components.py,sha256=7y2UWaIU0wBl44xO0SkU1m04ixbj4gd_FP9wFpsuZhY,7609
8
8
  flock/correlation_engine.py,sha256=iGB6-G5F-B-pw-clLx4-pZEiUrK_Q2l3kOn4jtEO_kw,8103
9
9
  flock/examples.py,sha256=eQb8k6EYBbUhauFuSN_0EIIu5KW0mTqJU0HM4-p14sc,3632
10
- flock/orchestrator.py,sha256=4ZXu8tc-hBw73Y47ZQvVh7vuLq1JOjT45xaRP7Umsc8,48514
10
+ flock/orchestrator.py,sha256=YJ8M7HxCUjq4hZ9wj3XKbOfLPVq-_zeTPclhI0YBaA0,54530
11
11
  flock/registry.py,sha256=s0-H-TMtOsDZiZQCc7T1tYiWQg3OZHn5T--jaI_INIc,4786
12
- flock/runtime.py,sha256=UG-38u578h628mSddBmyZn2VIzFQ0wlHCpCALFiScqA,8518
12
+ flock/runtime.py,sha256=uEq_zpCd--zqVAGU95uQt9QXqp2036iWo2lRr1JGlM8,8651
13
13
  flock/service.py,sha256=JDdjjPTPH6NFezAr8x6svtqxIGXA7-AyHS11GF57g9Q,11041
14
14
  flock/store.py,sha256=H6z1_y5uDp_4UnHWqrxNksyoSGlzeVTgLY3Sv-guSTU,45793
15
15
  flock/subscription.py,sha256=0fqjGVAr-3u1azSsXJ-xVjnUgSSYVO2a0Gd_zln2tZA,5422
@@ -25,20 +25,22 @@ flock/dashboard/service.py,sha256=_jyHQ_hC9sFgj8mwtuW2r8labZ3NsBJ-1FYcKB0qq9E,52
25
25
  flock/dashboard/websocket.py,sha256=_DCZApJPXc8OQnxFDFS9TA9ozq7kM73QByRj-_a8n-8,9508
26
26
  flock/dashboard/models/__init__.py,sha256=T4Yz8IXMm7lBqa2HLDSv7WJBtaKcdZIlTrz6GHNFZxs,68
27
27
  flock/dashboard/models/graph.py,sha256=oQAGAVMV32tim8xscUxZ9nFOci0RvryjdPf1sJgiGxQ,5402
28
- flock/dashboard/static_v2/index.html,sha256=iWL-fgTY2egom20DMvSOpuYZ6pC5AVvdNZcj-EvPm5w,422
29
- flock/dashboard/static_v2/assets/index-DFRnI_mt.js,sha256=PVrBXxY3Igbf9dqtsWoCbhogEhibapLAwlMYV5Gv4pY,764870
28
+ flock/dashboard/static_v2/index.html,sha256=0KNfWwmpr0JmVNbalnsaQta0y3XlVhOQ_HSts2LuU3A,423
29
+ flock/dashboard/static_v2/assets/index-DFRnI_mt.js,sha256=qeezaWLISr_EKNBBh8v0jzspd2KRcz8jW1r0p7z0Ht0,764860
30
30
  flock/dashboard/static_v2/assets/index-fPLNdmp1.css,sha256=skpvfkkrlw7WbmBh7HN-rUKAtKP-gpuLUH4klUgFHT4,74529
31
31
  flock/engines/__init__.py,sha256=waNyObJ8PKCLFZL3WUFynxSK-V47m559P3Px-vl_OSc,124
32
- flock/engines/dspy_engine.py,sha256=o_k9mnWuxGN2jEL8KQmaBCGi6Aw8hQb9AZPsQRLRw3U,50921
33
- flock/frontend/README.md,sha256=R1gqm524Xa5PZAkfl-IJDEf6VsBJ6ThrpY7SyDawjog,26232
32
+ flock/engines/dspy_engine.py,sha256=Q2stZi6jMjjNlhXvzmW3m-Y8AdVo1QuNunbnxEZl6rA,52232
33
+ flock/engines/examples/__init__.py,sha256=cDAjF8_NPL7nhpwa_xxgnPYRAXZWppKE2HkxmL8LGAI,126
34
+ flock/engines/examples/simple_batch_engine.py,sha256=RZVuFJHr3j_4dJZc2AXUcjKZJdct0A7UKOSwWgVEKk4,2235
35
+ flock/frontend/README.md,sha256=0dEzu4UxacGfSstz9_R0KSeFWJ1vNRi0p-KLIay_TfU,26212
34
36
  flock/frontend/index.html,sha256=BFg1VR_YVAJ_MGN16xa7sT6wTGwtFYUhfJhGuKv89VM,312
35
- flock/frontend/package-lock.json,sha256=1edo2JDle0if_MljnK4Xto7Q7hhGUEBQAvQFqKy9RzQ,150798
36
- flock/frontend/package.json,sha256=pFYRQHNOpZnamMFzOOvS1McUBNPZXeNusIbQaJxdnnc,1258
37
+ flock/frontend/package-lock.json,sha256=vNOaISeq3EfEDDEsFYPWFaMsqypDgQIE0P_u6tzE0g4,150798
38
+ flock/frontend/package.json,sha256=SFwHeNZ0mS9p4_enSXZNMtuXxSM5cl52dzEr-MuRZ90,1253
37
39
  flock/frontend/tsconfig.json,sha256=B9p9jXohg_jrCZAq5_yIHvznpeXHiHQkwUZrVE2oMRA,705
38
40
  flock/frontend/tsconfig.node.json,sha256=u5_YWSqeNkZBRBIZ8Q2E2q6bospcyF23mO-taRO7glc,233
39
41
  flock/frontend/vite.config.ts,sha256=M76uTsyn7fvHI4NhaGyizOGmml0fJvuhSljOQm_UvGs,566
40
42
  flock/frontend/vitest.config.ts,sha256=xSWyGrBv2Cy_5eeZA68NCO5AXS6q8WKZXXzqu2JnXPY,244
41
- flock/frontend/docs/DESIGN_SYSTEM.md,sha256=xDTKBDikSIyJMP5Lk0gWSimQHeXv8IzIuJR7SLOEdPY,48503
43
+ flock/frontend/docs/DESIGN_SYSTEM.md,sha256=a7hbH7kQCOrOQu3CMTYthTZTrFCQUIRcqtXaYHMkPbo,48498
42
44
  flock/frontend/src/App.tsx,sha256=3vwTT_WJP7OUb0LJDVMXfkb5hD-uZZmiGBK2wl1QgeM,5233
43
45
  flock/frontend/src/main.tsx,sha256=sfWsPgNn5AyDH4LJJLTz2c5OwOPl0o4oi-FArpqc-W4,354
44
46
  flock/frontend/src/vite-env.d.ts,sha256=tDjMtvUVN9uIgSCHe__Jhp0-nZiIV21pkcQuyOjaryw,344
@@ -112,9 +114,9 @@ flock/frontend/src/components/settings/AdvancedSettings.tsx,sha256=Ngw5jAIRn3ocX
112
114
  flock/frontend/src/components/settings/AppearanceSettings.tsx,sha256=UHH4BcJ9-F-nRJEJf2rzmX0W-0hvmeKo6AYNF3lZPWE,6872
113
115
  flock/frontend/src/components/settings/GraphSettings.tsx,sha256=qX1F4hnsxGcCbn3oHP7nsPPMLyETHG3UL55kJ_3tA-s,3815
114
116
  flock/frontend/src/components/settings/MultiSelect.tsx,sha256=aFjk8pt18UFHIPh-MXxEepjh-haNYhxEwzMiewSKFbU,7005
115
- flock/frontend/src/components/settings/SettingsPanel.css,sha256=5ThwfEexKrXEQ_Z73tcA_rg2HxxV2vuptSuuuvwHURY,7067
117
+ flock/frontend/src/components/settings/SettingsPanel.css,sha256=SUUfMHGXVxX8GDDQcb0f6v7ZG983tXa9pC6Xrwctep8,7062
116
118
  flock/frontend/src/components/settings/SettingsPanel.tsx,sha256=62GXPCQzYdbk17XYVOx_vCeWlVyFZSxp3w0JTkp3z60,4392
117
- flock/frontend/src/components/settings/ThemeSelector.tsx,sha256=LDTaqFzWPa7Uw3IRp60l6TI5dLvfsel-Xl3GhuCuf30,10548
119
+ flock/frontend/src/components/settings/ThemeSelector.tsx,sha256=FqyRtWhN8vm6cxfPI1pxFCCuCFDb4YXrwzdufwrXFqM,10538
118
120
  flock/frontend/src/components/settings/TracingSettings.tsx,sha256=zHZrUuVQzUANclHfvTndm50zHYX1y-LecFnrloh2Hkc,14224
119
121
  flock/frontend/src/hooks/useKeyboardShortcuts.ts,sha256=Dsf64nPtJdW2kV-a-bBpaq1VXZkXyxpioBnI1WIGduM,5019
120
122
  flock/frontend/src/hooks/useModulePersistence.test.ts,sha256=kqYlFSzqYK_0jGxeRTeXORZ2KTDo3MdByJ2t2ivbg20,14323
@@ -125,7 +127,7 @@ flock/frontend/src/services/api.ts,sha256=kNHBHvbSk50M3pUtwDMNYwco5Cd4AbQbGGHkpR
125
127
  flock/frontend/src/services/graphService.test.ts,sha256=wftS4QX-Bw6hogTWXVYaV3F7z6AN94d7iI8jrMVwwkg,11493
126
128
  flock/frontend/src/services/graphService.ts,sha256=MaFdj8S2l7UOkQBkACDv29BuroMy1vJEhliVnsYkmwM,1964
127
129
  flock/frontend/src/services/indexeddb.test.ts,sha256=lY1JzyKRd4Kaw135JlO7njy5rpaAsRRXLM8SwYxDhAc,27452
128
- flock/frontend/src/services/indexeddb.ts,sha256=gSTkrR-JJlN9ovDuLK45uQrYSrS2dwgOcy14C1pvNdY,28708
130
+ flock/frontend/src/services/indexeddb.ts,sha256=2sXodUZAp3jSiS-3a7Bwvkjdjp_Tc47bk5eR_1f9qqw,28703
129
131
  flock/frontend/src/services/layout.test.ts,sha256=-KwUxWCum_Rsyc5NIpk99UB3prfAkMO5ksJULhjOiwA,16174
130
132
  flock/frontend/src/services/layout.ts,sha256=5WzlOv7OBlQXiUxrv4l1JwaAfHbUK1C99JOT0fQCNRY,9503
131
133
  flock/frontend/src/services/themeApplicator.ts,sha256=utRFw-45e1IEOrI6lHkB_E_-5kc2kFKbN-veAUdXiOM,5802
@@ -144,7 +146,7 @@ flock/frontend/src/store/uiStore.ts,sha256=H5aH8YfaxOTfm3zCrT9A1QdC2dnHJWPUUg8uV
144
146
  flock/frontend/src/store/wsStore.ts,sha256=vKaGd6H7UONN7A-8tCTOgdH8X2LxrZmVbZ7hRnfGQ2c,936
145
147
  flock/frontend/src/styles/index.css,sha256=HVMvVEMvlFk8_vqxBdt8CzkleXkV-oSUcQUzom588PM,231
146
148
  flock/frontend/src/styles/scrollbar.css,sha256=OHH2nryMANNvuJBloG_t1BPY_BtKMSb36Df4q2X47Rk,1207
147
- flock/frontend/src/styles/variables.css,sha256=EcOH8mb8ZIoGZU5c-K_2zcuGdtbu_vQWk_gC-X6vtmk,13889
149
+ flock/frontend/src/styles/variables.css,sha256=18UzMGPn_GOKWa2eXe1u0lJLI4yRLM7LjONASATwo6Q,13884
148
150
  flock/frontend/src/test/setup.ts,sha256=pG1mhRrywFboBf3VdL9ew62xGBxDxeQfChxZLjOK_mQ,36
149
151
  flock/frontend/src/types/filters.ts,sha256=zPa4AvL9xudvB6RZsqJCllMoLTnvPuBhqU6vLeWO89Y,1041
150
152
  flock/frontend/src/types/graph.ts,sha256=mz62owu0OXO-xbzCPX2_arRRv0_Kp79tj5Ek-TqdHhI,4615
@@ -527,8 +529,8 @@ flock/themes/zenburned.toml,sha256=UEmquBbcAO3Zj652XKUwCsNoC2iQSlIh-q5c6DH-7Kc,1
527
529
  flock/themes/zenwritten-dark.toml,sha256=-dgaUfg1iCr5Dv4UEeHv_cN4GrPUCWAiHSxWK20X1kI,1663
528
530
  flock/themes/zenwritten-light.toml,sha256=G1iEheCPfBNsMTGaVpEVpDzYBHA_T-MV27rolUYolmE,1666
529
531
  flock/utility/output_utility_component.py,sha256=yVHhlIIIoYKziI5UyT_zvQb4G-NsxCTgLwA1wXXTTj4,9047
530
- flock_core-0.5.4.dist-info/METADATA,sha256=sIKw84B11Gf4oxfpgvt6JS350aRzrc0exuhlsSHDKnY,39340
531
- flock_core-0.5.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
532
- flock_core-0.5.4.dist-info/entry_points.txt,sha256=UQdPmtHd97gSA_IdLt9MOd-1rrf_WO-qsQeIiHWVrp4,42
533
- flock_core-0.5.4.dist-info/licenses/LICENSE,sha256=U3IZuTbC0yLj7huwJdldLBipSOHF4cPf6cUOodFiaBE,1072
534
- flock_core-0.5.4.dist-info/RECORD,,
532
+ flock_core-0.5.5.dist-info/METADATA,sha256=t-87LUTaHtfmkBW4U37oAhenOGcoq3WITQfRpuvrgsc,39584
533
+ flock_core-0.5.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
534
+ flock_core-0.5.5.dist-info/entry_points.txt,sha256=UQdPmtHd97gSA_IdLt9MOd-1rrf_WO-qsQeIiHWVrp4,42
535
+ flock_core-0.5.5.dist-info/licenses/LICENSE,sha256=U3IZuTbC0yLj7huwJdldLBipSOHF4cPf6cUOodFiaBE,1072
536
+ flock_core-0.5.5.dist-info/RECORD,,