flock-core 0.5.5__py3-none-any.whl → 0.5.6__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 CHANGED
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import asyncio
6
6
  import os
7
+ from collections.abc import Sequence
7
8
  from dataclasses import dataclass
8
9
  from typing import TYPE_CHECKING, Any, TypedDict
9
10
 
@@ -118,6 +119,31 @@ class Agent(metaclass=AutoTracedMeta):
118
119
  def identity(self) -> AgentIdentity:
119
120
  return AgentIdentity(name=self.name, labels=self.labels, tenant_id=self.tenant_id)
120
121
 
122
+ @staticmethod
123
+ def _component_display_name(component: AgentComponent) -> str:
124
+ return component.name or component.__class__.__name__
125
+
126
+ def _sorted_utilities(self) -> list[AgentComponent]:
127
+ if not self.utilities:
128
+ return []
129
+ return sorted(self.utilities, key=lambda comp: getattr(comp, "priority", 0))
130
+
131
+ def _add_utilities(self, components: Sequence[AgentComponent]) -> None:
132
+ if not components:
133
+ return
134
+ for component in components:
135
+ self.utilities.append(component)
136
+ comp_name = self._component_display_name(component)
137
+ priority = getattr(component, "priority", 0)
138
+ logger.info(
139
+ "Agent %s: utility added: component=%s, priority=%s, total_utilities=%s",
140
+ self.name,
141
+ comp_name,
142
+ priority,
143
+ len(self.utilities),
144
+ )
145
+ self.utilities.sort(key=lambda comp: getattr(comp, "priority", 0))
146
+
121
147
  def set_max_concurrency(self, value: int) -> None:
122
148
  self.max_concurrency = max(1, value)
123
149
  self._semaphore = asyncio.Semaphore(self.max_concurrency)
@@ -221,21 +247,59 @@ class Agent(metaclass=AutoTracedMeta):
221
247
  return []
222
248
 
223
249
  async def _run_initialize(self, ctx: Context) -> None:
224
- for component in self.utilities:
225
- await component.on_initialize(self, ctx)
250
+ for component in self._sorted_utilities():
251
+ comp_name = self._component_display_name(component)
252
+ priority = getattr(component, "priority", 0)
253
+ logger.debug(
254
+ f"Agent initialize: agent={self.name}, component={comp_name}, priority={priority}"
255
+ )
256
+ try:
257
+ await component.on_initialize(self, ctx)
258
+ except Exception as exc:
259
+ logger.exception(
260
+ f"Agent initialize failed: agent={self.name}, component={comp_name}, "
261
+ f"priority={priority}, error={exc!s}"
262
+ )
263
+ raise
226
264
  for engine in self.engines:
227
265
  await engine.on_initialize(self, ctx)
228
266
 
229
267
  async def _run_pre_consume(self, ctx: Context, inputs: list[Artifact]) -> list[Artifact]:
230
268
  current = inputs
231
- for component in self.utilities:
232
- current = await component.on_pre_consume(self, ctx, current)
269
+ for component in self._sorted_utilities():
270
+ comp_name = self._component_display_name(component)
271
+ priority = getattr(component, "priority", 0)
272
+ logger.debug(
273
+ f"Agent pre_consume: agent={self.name}, component={comp_name}, "
274
+ f"priority={priority}, input_count={len(current)}"
275
+ )
276
+ try:
277
+ current = await component.on_pre_consume(self, ctx, current)
278
+ except Exception as exc:
279
+ logger.exception(
280
+ f"Agent pre_consume failed: agent={self.name}, component={comp_name}, "
281
+ f"priority={priority}, error={exc!s}"
282
+ )
283
+ raise
233
284
  return current
234
285
 
235
286
  async def _run_pre_evaluate(self, ctx: Context, inputs: EvalInputs) -> EvalInputs:
236
287
  current = inputs
237
- for component in self.utilities:
238
- current = await component.on_pre_evaluate(self, ctx, current)
288
+ for component in self._sorted_utilities():
289
+ comp_name = self._component_display_name(component)
290
+ priority = getattr(component, "priority", 0)
291
+ logger.debug(
292
+ f"Agent pre_evaluate: agent={self.name}, component={comp_name}, "
293
+ f"priority={priority}, artifact_count={len(current.artifacts)}"
294
+ )
295
+ try:
296
+ current = await component.on_pre_evaluate(self, ctx, current)
297
+ except Exception as exc:
298
+ logger.exception(
299
+ f"Agent pre_evaluate failed: agent={self.name}, component={comp_name}, "
300
+ f"priority={priority}, error={exc!s}"
301
+ )
302
+ raise
239
303
  return current
240
304
 
241
305
  async def _run_engines(self, ctx: Context, inputs: EvalInputs) -> EvalResult:
@@ -263,7 +327,7 @@ class Agent(metaclass=AutoTracedMeta):
263
327
  result = await engine.evaluate(self, ctx, current_inputs)
264
328
  except NotImplementedError:
265
329
  if use_batch_mode:
266
- logger.error(
330
+ logger.exception(
267
331
  "Agent %s: engine %s does not implement evaluate_batch()",
268
332
  self.name,
269
333
  engine.__class__.__name__,
@@ -310,8 +374,21 @@ class Agent(metaclass=AutoTracedMeta):
310
374
  self, ctx: Context, inputs: EvalInputs, result: EvalResult
311
375
  ) -> EvalResult:
312
376
  current = result
313
- for component in self.utilities:
314
- current = await component.on_post_evaluate(self, ctx, inputs, current)
377
+ for component in self._sorted_utilities():
378
+ comp_name = self._component_display_name(component)
379
+ priority = getattr(component, "priority", 0)
380
+ logger.debug(
381
+ f"Agent post_evaluate: agent={self.name}, component={comp_name}, "
382
+ f"priority={priority}, artifact_count={len(current.artifacts)}"
383
+ )
384
+ try:
385
+ current = await component.on_post_evaluate(self, ctx, inputs, current)
386
+ except Exception as exc:
387
+ logger.exception(
388
+ f"Agent post_evaluate failed: agent={self.name}, component={comp_name}, "
389
+ f"priority={priority}, error={exc!s}"
390
+ )
391
+ raise
315
392
  return current
316
393
 
317
394
  async def _make_outputs(self, ctx: Context, result: EvalResult) -> list[Artifact]:
@@ -341,9 +418,23 @@ class Agent(metaclass=AutoTracedMeta):
341
418
  return produced
342
419
 
343
420
  async def _run_post_publish(self, ctx: Context, artifacts: Sequence[Artifact]) -> None:
421
+ components = self._sorted_utilities()
344
422
  for artifact in artifacts:
345
- for component in self.utilities:
346
- await component.on_post_publish(self, ctx, artifact)
423
+ for component in components:
424
+ comp_name = self._component_display_name(component)
425
+ priority = getattr(component, "priority", 0)
426
+ logger.debug(
427
+ f"Agent post_publish: agent={self.name}, component={comp_name}, "
428
+ f"priority={priority}, artifact_id={artifact.id}"
429
+ )
430
+ try:
431
+ await component.on_post_publish(self, ctx, artifact)
432
+ except Exception as exc:
433
+ logger.exception(
434
+ f"Agent post_publish failed: agent={self.name}, component={comp_name}, "
435
+ f"priority={priority}, artifact_id={artifact.id}, error={exc!s}"
436
+ )
437
+ raise
347
438
 
348
439
  async def _invoke_call(self, ctx: Context, artifacts: Sequence[Artifact]) -> None:
349
440
  func = self.calls_func
@@ -359,14 +450,39 @@ class Agent(metaclass=AutoTracedMeta):
359
450
  await maybe_coro
360
451
 
361
452
  async def _run_error(self, ctx: Context, error: Exception) -> None:
362
- for component in self.utilities:
363
- await component.on_error(self, ctx, error)
453
+ for component in self._sorted_utilities():
454
+ comp_name = self._component_display_name(component)
455
+ priority = getattr(component, "priority", 0)
456
+ logger.debug(
457
+ f"Agent error hook: agent={self.name}, component={comp_name}, "
458
+ f"priority={priority}, error={error!s}"
459
+ )
460
+ try:
461
+ await component.on_error(self, ctx, error)
462
+ except Exception as exc:
463
+ logger.exception(
464
+ f"Agent error hook failed: agent={self.name}, component={comp_name}, "
465
+ f"priority={priority}, original_error={error!s}, hook_error={exc!s}"
466
+ )
467
+ raise
364
468
  for engine in self.engines:
365
469
  await engine.on_error(self, ctx, error)
366
470
 
367
471
  async def _run_terminate(self, ctx: Context) -> None:
368
- for component in self.utilities:
369
- await component.on_terminate(self, ctx)
472
+ for component in self._sorted_utilities():
473
+ comp_name = self._component_display_name(component)
474
+ priority = getattr(component, "priority", 0)
475
+ logger.debug(
476
+ f"Agent terminate: agent={self.name}, component={comp_name}, priority={priority}"
477
+ )
478
+ try:
479
+ await component.on_terminate(self, ctx)
480
+ except Exception as exc:
481
+ logger.exception(
482
+ f"Agent terminate failed: agent={self.name}, component={comp_name}, "
483
+ f"priority={priority}, error={exc!s}"
484
+ )
485
+ raise
370
486
  for engine in self.engines:
371
487
  await engine.on_terminate(self, ctx)
372
488
 
@@ -396,7 +512,7 @@ class Agent(metaclass=AutoTracedMeta):
396
512
  return []
397
513
 
398
514
  default_component = OutputUtilityComponent()
399
- self.utilities = [default_component]
515
+ self._add_utilities([default_component])
400
516
  return self.utilities
401
517
 
402
518
  def _find_matching_artifact(
@@ -672,7 +788,8 @@ class AgentBuilder:
672
788
  - AgentComponent: Base class for custom components
673
789
  - Lifecycle hooks: on_initialize, on_pre_consume, on_post_publish, etc.
674
790
  """
675
- self._agent.utilities.extend(components)
791
+ if components:
792
+ self._agent._add_utilities(list(components))
676
793
  return self
677
794
 
678
795
  def with_engines(self, *engines: EngineComponent) -> AgentBuilder:
flock/components.py CHANGED
@@ -56,6 +56,10 @@ class AgentComponent(BaseModel, metaclass=TracedModelMeta):
56
56
 
57
57
  name: str | None = None
58
58
  config: AgentComponentConfig = Field(default_factory=AgentComponentConfig)
59
+ priority: int = Field(
60
+ default=0,
61
+ description="Execution priority (lower numbers run earlier; default preserves add order).",
62
+ )
59
63
 
60
64
  async def on_initialize(
61
65
  self, agent: Agent, ctx: Context
@@ -98,6 +98,8 @@ class DashboardEventCollector(AgentComponent):
98
98
  Phase 3: Emits events via WebSocket using WebSocketManager.
99
99
  """
100
100
 
101
+ priority: int = -100 # Run before other agent utilities for event capture
102
+
101
103
  # Use PrivateAttr for non-Pydantic fields (AgentComponent extends BaseModel)
102
104
  _events: deque[
103
105
  AgentActivatedEvent | MessagePublishedEvent | AgentCompletedEvent | AgentErrorEvent