flock-core 0.4.520__py3-none-any.whl → 0.5.0b1__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 (103) hide show
  1. flock/cli/manage_agents.py +3 -3
  2. flock/components/__init__.py +28 -0
  3. flock/components/evaluation/__init__.py +9 -0
  4. flock/components/evaluation/declarative_evaluation_component.py +198 -0
  5. flock/components/routing/__init__.py +15 -0
  6. flock/{routers/conditional/conditional_router.py → components/routing/conditional_routing_component.py} +60 -49
  7. flock/components/routing/default_routing_component.py +103 -0
  8. flock/components/routing/llm_routing_component.py +208 -0
  9. flock/components/utility/__init__.py +15 -0
  10. flock/{modules/enterprise_memory/enterprise_memory_module.py → components/utility/memory_utility_component.py} +195 -173
  11. flock/{modules/performance/metrics_module.py → components/utility/metrics_utility_component.py} +101 -86
  12. flock/{modules/output/output_module.py → components/utility/output_utility_component.py} +49 -49
  13. flock/core/__init__.py +2 -8
  14. flock/core/agent/__init__.py +16 -0
  15. flock/core/agent/flock_agent_components.py +104 -0
  16. flock/core/agent/flock_agent_execution.py +101 -0
  17. flock/core/agent/flock_agent_integration.py +147 -0
  18. flock/core/agent/flock_agent_lifecycle.py +177 -0
  19. flock/core/agent/flock_agent_serialization.py +378 -0
  20. flock/core/component/__init__.py +15 -0
  21. flock/core/{flock_module.py → component/agent_component_base.py} +136 -35
  22. flock/core/component/evaluation_component_base.py +56 -0
  23. flock/core/component/routing_component_base.py +75 -0
  24. flock/core/component/utility_component_base.py +69 -0
  25. flock/core/config/flock_agent_config.py +49 -2
  26. flock/core/evaluation/utils.py +1 -1
  27. flock/core/execution/evaluation_executor.py +1 -1
  28. flock/core/flock.py +137 -483
  29. flock/core/flock_agent.py +151 -1018
  30. flock/core/flock_factory.py +94 -73
  31. flock/core/{flock_registry.py → flock_registry.py.backup} +3 -17
  32. flock/core/logging/logging.py +1 -0
  33. flock/core/mcp/flock_mcp_server.py +42 -37
  34. flock/core/mixin/dspy_integration.py +5 -5
  35. flock/core/orchestration/__init__.py +18 -0
  36. flock/core/orchestration/flock_batch_processor.py +94 -0
  37. flock/core/orchestration/flock_evaluator.py +113 -0
  38. flock/core/orchestration/flock_execution.py +288 -0
  39. flock/core/orchestration/flock_initialization.py +125 -0
  40. flock/core/orchestration/flock_server_manager.py +65 -0
  41. flock/core/orchestration/flock_web_server.py +117 -0
  42. flock/core/registry/__init__.py +39 -0
  43. flock/core/registry/agent_registry.py +69 -0
  44. flock/core/registry/callable_registry.py +139 -0
  45. flock/core/registry/component_discovery.py +142 -0
  46. flock/core/registry/component_registry.py +64 -0
  47. flock/core/registry/config_mapping.py +64 -0
  48. flock/core/registry/decorators.py +137 -0
  49. flock/core/registry/registry_hub.py +202 -0
  50. flock/core/registry/server_registry.py +57 -0
  51. flock/core/registry/type_registry.py +86 -0
  52. flock/core/serialization/flock_serializer.py +33 -30
  53. flock/core/serialization/serialization_utils.py +28 -25
  54. flock/core/util/input_resolver.py +29 -2
  55. flock/platform/docker_tools.py +3 -3
  56. flock/tools/markdown_tools.py +1 -2
  57. flock/tools/text_tools.py +1 -2
  58. flock/webapp/app/main.py +9 -5
  59. flock/workflow/activities.py +59 -84
  60. flock/workflow/activities_unified.py +230 -0
  61. flock/workflow/agent_execution_activity.py +6 -6
  62. flock/workflow/flock_workflow.py +1 -1
  63. {flock_core-0.4.520.dist-info → flock_core-0.5.0b1.dist-info}/METADATA +2 -2
  64. {flock_core-0.4.520.dist-info → flock_core-0.5.0b1.dist-info}/RECORD +67 -68
  65. flock/core/flock_evaluator.py +0 -60
  66. flock/core/flock_router.py +0 -83
  67. flock/evaluators/__init__.py +0 -1
  68. flock/evaluators/declarative/__init__.py +0 -1
  69. flock/evaluators/declarative/declarative_evaluator.py +0 -194
  70. flock/evaluators/memory/memory_evaluator.py +0 -90
  71. flock/evaluators/test/test_case_evaluator.py +0 -38
  72. flock/evaluators/zep/zep_evaluator.py +0 -59
  73. flock/modules/__init__.py +0 -1
  74. flock/modules/assertion/__init__.py +0 -1
  75. flock/modules/assertion/assertion_module.py +0 -286
  76. flock/modules/callback/__init__.py +0 -1
  77. flock/modules/callback/callback_module.py +0 -91
  78. flock/modules/enterprise_memory/README.md +0 -99
  79. flock/modules/mem0/__init__.py +0 -1
  80. flock/modules/mem0/mem0_module.py +0 -126
  81. flock/modules/mem0_async/__init__.py +0 -1
  82. flock/modules/mem0_async/async_mem0_module.py +0 -126
  83. flock/modules/memory/__init__.py +0 -1
  84. flock/modules/memory/memory_module.py +0 -429
  85. flock/modules/memory/memory_parser.py +0 -125
  86. flock/modules/memory/memory_storage.py +0 -736
  87. flock/modules/output/__init__.py +0 -1
  88. flock/modules/performance/__init__.py +0 -1
  89. flock/modules/zep/__init__.py +0 -1
  90. flock/modules/zep/zep_module.py +0 -192
  91. flock/routers/__init__.py +0 -1
  92. flock/routers/agent/__init__.py +0 -1
  93. flock/routers/agent/agent_router.py +0 -236
  94. flock/routers/agent/handoff_agent.py +0 -58
  95. flock/routers/default/__init__.py +0 -1
  96. flock/routers/default/default_router.py +0 -80
  97. flock/routers/feedback/feedback_router.py +0 -114
  98. flock/routers/list_generator/list_generator_router.py +0 -166
  99. flock/routers/llm/__init__.py +0 -1
  100. flock/routers/llm/llm_router.py +0 -365
  101. {flock_core-0.4.520.dist-info → flock_core-0.5.0b1.dist-info}/WHEEL +0 -0
  102. {flock_core-0.4.520.dist-info → flock_core-0.5.0b1.dist-info}/entry_points.txt +0 -0
  103. {flock_core-0.4.520.dist-info → flock_core-0.5.0b1.dist-info}/licenses/LICENSE +0 -0
@@ -1,22 +1,26 @@
1
- """Performance and metrics tracking for Flock agents."""
1
+ # src/flock/components/utility/metrics_utility_component.py
2
+ """Performance and metrics tracking for Flock agents using unified component architecture."""
2
3
 
3
4
  import json
4
5
  import os
5
6
  import time
6
7
  from collections import defaultdict
7
8
  from datetime import datetime
8
- from typing import Any, Literal
9
+ from typing import TYPE_CHECKING, Any, Literal
9
10
 
10
11
  import numpy as np
11
12
  import psutil
12
- from pydantic import BaseModel, Field, validator
13
+ from pydantic import BaseModel, Field, field_validator
13
14
 
15
+ from flock.core.component.agent_component_base import AgentComponentConfig
16
+ from flock.core.component.utility_component_base import UtilityComponentBase
14
17
  from flock.core.context.context import FlockContext
15
- from flock.core.flock_agent import FlockAgent
16
- from flock.core.flock_module import FlockModule, FlockModuleConfig
17
- from flock.core.flock_registry import flock_component
18
+ from flock.core.registry import flock_component
18
19
  from flock.core.mcp.flock_mcp_server import FlockMCPServerBase
19
20
 
21
+ if TYPE_CHECKING:
22
+ from flock.core.flock_agent import FlockAgent
23
+
20
24
 
21
25
  class MetricPoint(BaseModel):
22
26
  """Single metric measurement."""
@@ -25,11 +29,10 @@ class MetricPoint(BaseModel):
25
29
  value: int | float | str
26
30
  tags: dict[str, str] = {}
27
31
 
28
- class Config:
29
- arbitrary_types_allowed = True
32
+ model_config = {"arbitrary_types_allowed": True}
30
33
 
31
34
 
32
- class MetricsModuleConfig(FlockModuleConfig):
35
+ class MetricsUtilityConfig(AgentComponentConfig):
33
36
  """Configuration for performance metrics collection."""
34
37
 
35
38
  # Collection settings
@@ -66,7 +69,8 @@ class MetricsModuleConfig(FlockModuleConfig):
66
69
  default=1000, description="Threshold for latency alerts"
67
70
  )
68
71
 
69
- @validator("aggregation_interval")
72
+ @field_validator("aggregation_interval")
73
+ @classmethod
70
74
  def validate_interval(cls, v):
71
75
  """Validate time interval format."""
72
76
  if v[-1] not in ["s", "m", "h", "d"]:
@@ -74,23 +78,30 @@ class MetricsModuleConfig(FlockModuleConfig):
74
78
  return v
75
79
 
76
80
 
77
- @flock_component(config_class=MetricsModuleConfig)
78
- class MetricsModule(FlockModule):
79
- """Module for collecting and analyzing agent performance metrics."""
81
+ @flock_component(config_class=MetricsUtilityConfig)
82
+ class MetricsUtilityComponent(UtilityComponentBase):
83
+ """Utility component for collecting and analyzing agent performance metrics."""
80
84
 
81
85
  # --- Singleton holder for convenient static access ---
82
- _INSTANCE: "MetricsModule | None" = None
86
+ _INSTANCE: "MetricsUtilityComponent | None" = None
83
87
 
84
- name: str = "performance_metrics"
85
- config: MetricsModuleConfig = Field(
86
- default_factory=MetricsModuleConfig,
88
+ config: MetricsUtilityConfig = Field(
89
+ default_factory=MetricsUtilityConfig,
87
90
  description="Performance metrics configuration",
88
91
  )
89
92
 
90
- def __init__(self, name, config):
91
- super().__init__(name=name, config=config)
93
+ def __init__(
94
+ self,
95
+ name: str = "metrics",
96
+ config: MetricsUtilityConfig | None = None,
97
+ **data,
98
+ ):
99
+ if config is None:
100
+ config = MetricsUtilityConfig()
101
+ super().__init__(name=name, config=config, **data)
102
+
92
103
  # Register singleton for static helpers
93
- MetricsModule._INSTANCE = self
104
+ MetricsUtilityComponent._INSTANCE = self
94
105
  self._metrics = defaultdict(list)
95
106
  self._start_time: float | None = None
96
107
  self._server_start_time: float | None = None
@@ -130,8 +141,6 @@ class MetricsModule(FlockModule):
130
141
  except ImportError:
131
142
  self.config.storage_type = "json"
132
143
 
133
- """Fixes for metrics summary calculation."""
134
-
135
144
  def _load_metrics_from_files(
136
145
  self, metric_name: str = None
137
146
  ) -> dict[str, list[MetricPoint]]:
@@ -236,40 +245,6 @@ class MetricsModule(FlockModule):
236
245
 
237
246
  return stats
238
247
 
239
- async def on_terminate(
240
- self,
241
- agent: FlockAgent,
242
- inputs: dict[str, Any],
243
- context: FlockContext | None = None,
244
- result: dict[str, Any] | None = None,
245
- ) -> None:
246
- """Clean up and final metric recording."""
247
- if self.config.storage_type == "json":
248
- # Save aggregated metrics
249
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
250
- summary_file = os.path.join(
251
- self.config.metrics_dir,
252
- f"summary_{agent.name}_{timestamp}.json",
253
- )
254
-
255
- # Calculate summary for all metrics
256
- summary = {
257
- "agent": agent.name,
258
- "timestamp": timestamp,
259
- "metrics": {},
260
- }
261
-
262
- # Get all unique metric names from files
263
- all_metrics = self._load_metrics_from_files()
264
-
265
- for metric_name in all_metrics:
266
- stats = self.get_statistics(metric_name)
267
- if stats: # Only include metrics that have data
268
- summary["metrics"][metric_name] = stats
269
-
270
- with open(summary_file, "w") as f:
271
- json.dump(summary, f, indent=2)
272
-
273
248
  def _record_metric(
274
249
  self, name: str, value: int | float | str, tags: dict[str, str] = None
275
250
  ) -> None:
@@ -342,29 +317,7 @@ class MetricsModule(FlockModule):
342
317
  print(
343
318
  f"Warning: Using estimated token count. Install tiktoken for accurate counting."
344
319
  )
345
-
346
- def _should_alert(self, metric: str, value: float) -> bool:
347
- """Check if metric should trigger alert."""
348
- if metric == "latency" and self.config.alert_on_high_latency:
349
- return value * 1000 > self.config.latency_threshold_ms
350
- return False
351
-
352
- async def on_initialize(
353
- self,
354
- agent: FlockAgent,
355
- inputs: dict[str, Any],
356
- context: FlockContext | None = None,
357
- ) -> None:
358
- """Initialize metrics collection."""
359
- self._start_time = time.time()
360
-
361
- if self.config.collect_memory:
362
- self._start_memory = psutil.Process().memory_info().rss
363
- self._record_metric(
364
- "memory",
365
- self._start_memory,
366
- {"agent": agent.name, "phase": "start"},
367
- )
320
+ return token_estimate
368
321
 
369
322
  def _calculate_cost(
370
323
  self, text: str, model: str, is_completion: bool = False
@@ -391,9 +344,32 @@ class MetricsModule(FlockModule):
391
344
  total_cost = 0.0
392
345
  return token_count, total_cost
393
346
 
347
+ def _should_alert(self, metric: str, value: float) -> bool:
348
+ """Check if metric should trigger alert."""
349
+ if metric == "latency" and self.config.alert_on_high_latency:
350
+ return value * 1000 > self.config.latency_threshold_ms
351
+ return False
352
+
353
+ async def on_initialize(
354
+ self,
355
+ agent: "FlockAgent",
356
+ inputs: dict[str, Any],
357
+ context: FlockContext | None = None,
358
+ ) -> None:
359
+ """Initialize metrics collection."""
360
+ self._start_time = time.time()
361
+
362
+ if self.config.collect_memory:
363
+ self._start_memory = psutil.Process().memory_info().rss
364
+ self._record_metric(
365
+ "memory",
366
+ self._start_memory,
367
+ {"agent": agent.name, "phase": "start"},
368
+ )
369
+
394
370
  async def on_pre_evaluate(
395
371
  self,
396
- agent: FlockAgent,
372
+ agent: "FlockAgent",
397
373
  inputs: dict[str, Any],
398
374
  context: FlockContext | None = None,
399
375
  ) -> dict[str, Any]:
@@ -434,7 +410,7 @@ class MetricsModule(FlockModule):
434
410
 
435
411
  async def on_post_evaluate(
436
412
  self,
437
- agent: FlockAgent,
413
+ agent: "FlockAgent",
438
414
  inputs: dict[str, Any],
439
415
  context: FlockContext | None = None,
440
416
  result: dict[str, Any] | None = None,
@@ -449,7 +425,7 @@ class MetricsModule(FlockModule):
449
425
  # In practice, you'd want to integrate with a proper alerting system
450
426
  print(f"ALERT: High latency detected: {latency * 1000:.2f}ms")
451
427
 
452
- if self.config.collect_token_usage:
428
+ if self.config.collect_token_usage and result:
453
429
  # Calculate output tokens and cost
454
430
  total_output_tokens = 0
455
431
  total_output_cost = 0.0
@@ -493,7 +469,7 @@ class MetricsModule(FlockModule):
493
469
 
494
470
  async def on_error(
495
471
  self,
496
- agent: FlockAgent,
472
+ agent: "FlockAgent",
497
473
  error: Exception,
498
474
  inputs: dict[str, Any],
499
475
  context: FlockContext | None = None,
@@ -505,16 +481,55 @@ class MetricsModule(FlockModule):
505
481
  {"agent": agent.name, "error_type": type(error).__name__},
506
482
  )
507
483
 
484
+ async def on_terminate(
485
+ self,
486
+ agent: "FlockAgent",
487
+ inputs: dict[str, Any],
488
+ context: FlockContext | None = None,
489
+ result: dict[str, Any] | None = None,
490
+ ) -> None:
491
+ """Clean up and final metric recording."""
492
+ if self.config.storage_type == "json":
493
+ # Save aggregated metrics
494
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
495
+ summary_file = os.path.join(
496
+ self.config.metrics_dir,
497
+ f"summary_{agent.name}_{timestamp}.json",
498
+ )
499
+
500
+ # Calculate summary for all metrics
501
+ summary = {
502
+ "agent": agent.name,
503
+ "timestamp": timestamp,
504
+ "metrics": {},
505
+ }
506
+
507
+ # Get all unique metric names from files
508
+ all_metrics = self._load_metrics_from_files()
509
+
510
+ for metric_name in all_metrics:
511
+ stats = self.get_statistics(metric_name)
512
+ if stats: # Only include metrics that have data
513
+ summary["metrics"][metric_name] = stats
514
+
515
+ with open(summary_file, "w") as f:
516
+ json.dump(summary, f, indent=2)
517
+
508
518
  # --------------------------------------------------
509
519
  # Public helper for external modules
510
520
  # --------------------------------------------------
511
521
  @classmethod
512
- def record(cls, name: str, value: int | float | str, tags: dict[str, str] | None = None):
522
+ def record(
523
+ cls,
524
+ name: str,
525
+ value: int | float | str,
526
+ tags: dict[str, str] | None = None,
527
+ ):
513
528
  """Record a metric from anywhere in the codebase.
514
529
 
515
530
  Example:
516
- MetricsModule.record("custom_latency", 123, {"stage": "inference"})
517
- The call will forward to the *first* instantiated MetricsModule. If no
531
+ MetricsUtilityComponent.record("custom_latency", 123, {"stage": "inference"})
532
+ The call will forward to the *first* instantiated MetricsUtilityComponent. If no
518
533
  instance exists in the current run the call is a no-op so that importing
519
534
  this helper never crashes test-code.
520
535
  """
@@ -1,31 +1,27 @@
1
- """Output formatting and display functionality for agents."""
1
+ # src/flock/components/utility/output_utility_component.py
2
+ """Output formatting and display functionality for agents using unified component architecture."""
2
3
 
4
+ import re
3
5
  from typing import TYPE_CHECKING, Any
4
6
 
5
7
  from pydantic import Field
6
8
 
7
- from flock.core.context.context_vars import FLOCK_BATCH_SILENT_MODE
8
- from flock.core.flock_registry import flock_component
9
-
10
- if TYPE_CHECKING:
11
- from flock.core import FlockAgent
12
-
9
+ from flock.core.component.agent_component_base import AgentComponentConfig
10
+ from flock.core.component.utility_component_base import UtilityComponentBase
13
11
  from flock.core.context.context import FlockContext
14
- from flock.core.flock_module import FlockModule, FlockModuleConfig
15
- from flock.core.logging.formatters.themed_formatter import (
16
- ThemedAgentResultFormatter,
17
- )
12
+ from flock.core.context.context_vars import FLOCK_BATCH_SILENT_MODE
13
+ from flock.core.registry import flock_component
14
+ from flock.core.logging.formatters.themed_formatter import ThemedAgentResultFormatter
18
15
  from flock.core.logging.formatters.themes import OutputTheme
19
16
  from flock.core.logging.logging import get_logger
20
17
 
21
- # from flock.core.logging.formatters.themes import OutputTheme
22
- # from flock.core.logging.logging import get_logger
23
- # from flock.core.serialization.json_encoder import FlockJSONEncoder
18
+ if TYPE_CHECKING:
19
+ from flock.core.flock_agent import FlockAgent
24
20
 
25
- logger = get_logger("module.output")
21
+ logger = get_logger("components.utility.output")
26
22
 
27
23
 
28
- class OutputModuleConfig(FlockModuleConfig):
24
+ class OutputUtilityConfig(AgentComponentConfig):
29
25
  """Configuration for output formatting and display."""
30
26
 
31
27
  theme: OutputTheme = Field(
@@ -61,17 +57,18 @@ class OutputModuleConfig(FlockModuleConfig):
61
57
  )
62
58
 
63
59
 
64
- @flock_component(config_class=OutputModuleConfig)
65
- class OutputModule(FlockModule):
66
- """Module that handles output formatting and display."""
60
+ @flock_component(config_class=OutputUtilityConfig)
61
+ class OutputUtilityComponent(UtilityComponentBase):
62
+ """Utility component that handles output formatting and display."""
67
63
 
68
- name: str = "output"
69
- config: OutputModuleConfig = Field(
70
- default_factory=OutputModuleConfig, description="Output configuration"
64
+ config: OutputUtilityConfig = Field(
65
+ default_factory=OutputUtilityConfig, description="Output configuration"
71
66
  )
72
67
 
73
- def __init__(self, name: str, config: OutputModuleConfig):
74
- super().__init__(name=name, config=config)
68
+ def __init__(self, name: str = "output", config: OutputUtilityConfig | None = None, **data):
69
+ if config is None:
70
+ config = OutputUtilityConfig()
71
+ super().__init__(name=name, config=config, **data)
75
72
  self._formatter = ThemedAgentResultFormatter(
76
73
  theme=self.config.theme,
77
74
  max_length=self.config.max_length,
@@ -98,34 +95,40 @@ class OutputModule(FlockModule):
98
95
 
99
96
  def _format_dict(self, d: dict[str, Any], indent: int = 0) -> str:
100
97
  """Format a dictionary with proper indentation."""
101
- lines = []
102
- for k, v in d.items():
103
- formatted_value = self._format_value(v, k)
104
- if (
105
- self.config.truncate_long_values
106
- and len(formatted_value) > self.config.max_length
107
- ):
108
- formatted_value = (
109
- formatted_value[: self.config.max_length] + "..."
110
- )
111
- lines.append(f"{' ' * indent}{k}: {formatted_value}")
112
- return "\n".join(lines)
98
+ if not d:
99
+ return "{}"
100
+
101
+ items = []
102
+ prefix = " " * indent
103
+ for key, value in d.items():
104
+ if self.config.truncate_long_values and isinstance(value, str) and len(value) > 100:
105
+ value = value[:97] + "..."
106
+ formatted_value = self._format_value(value, key)
107
+ items.append(f"{prefix} {key}: {formatted_value}")
108
+
109
+ return "{\n" + "\n".join(items) + f"\n{prefix}}}"
113
110
 
114
111
  def _format_list(self, lst: list[Any]) -> str:
115
- """Format a list with proper indentation."""
116
- return "\n".join(f"- {self._format_value(item, '')}" for item in lst)
112
+ """Format a list with proper structure."""
113
+ if not lst:
114
+ return "[]"
115
+
116
+ if len(lst) <= 3:
117
+ return str(lst)
118
+
119
+ # For longer lists, show first few items and count
120
+ preview = [str(item) for item in lst[:3]]
121
+ return f"[{', '.join(preview)}, ... ({len(lst)} total)]"
117
122
 
118
123
  def _format_potential_code(self, text: str) -> str:
119
- """Format text that might contain code blocks."""
120
- import re
121
-
124
+ """Apply syntax highlighting to potential code blocks."""
125
+ # Simple pattern matching for code blocks
122
126
  def replace_code_block(match):
127
+ language = match.group(1) or "text"
123
128
  code = match.group(2)
124
- lang = match.group(1) if match.group(1) else ""
125
- # Here you could add syntax highlighting
126
- return f"```{lang}\n{code}\n```"
127
-
128
- # Replace code blocks with formatted versions
129
+ return f"[CODE:{language}]\n{code}\n[/CODE]"
130
+
131
+ # Replace markdown-style code blocks
129
132
  text = re.sub(
130
133
  r"```(\w+)?\n(.*?)\n```", replace_code_block, text, flags=re.DOTALL
131
134
  )
@@ -174,7 +177,6 @@ class OutputModule(FlockModule):
174
177
  theme=self.config.theme,
175
178
  max_length=self.config.max_length,
176
179
  render_table=self.config.render_table,
177
- wait_for_input=self.config.wait_for_input,
178
180
  )
179
181
  self._formatter.display_result(result_to_display, agent.name)
180
182
 
@@ -187,8 +189,6 @@ class OutputModule(FlockModule):
187
189
  theme=self.config.theme,
188
190
  max_length=self.config.max_length,
189
191
  render_table=self.config.render_table,
190
- wait_for_input=self.config.wait_for_input,
191
- write_to_file=self.config.write_to_file,
192
192
  )
193
193
 
194
194
  def add_custom_formatter(self, key: str, formatter_name: str) -> None:
flock/core/__init__.py CHANGED
@@ -3,11 +3,9 @@
3
3
  from flock.core.context.context import FlockContext
4
4
  from flock.core.flock import Flock
5
5
  from flock.core.flock_agent import FlockAgent
6
- from flock.core.flock_evaluator import FlockEvaluator, FlockEvaluatorConfig
7
6
  from flock.core.flock_factory import FlockFactory
8
- from flock.core.flock_module import FlockModule, FlockModuleConfig
9
- from flock.core.flock_registry import (
10
- FlockRegistry,
7
+ from flock.core.registry import (
8
+ RegistryHub as FlockRegistry, # Keep FlockRegistry name for API compatibility
11
9
  flock_callable,
12
10
  flock_component,
13
11
  flock_tool,
@@ -25,16 +23,12 @@ __all__ = [
25
23
  "Flock",
26
24
  "FlockAgent",
27
25
  "FlockContext",
28
- "FlockEvaluator",
29
- "FlockEvaluatorConfig",
30
26
  "FlockFactory",
31
27
  "FlockMCPClientBase",
32
28
  "FlockMCPClientManagerBase",
33
29
  "FlockMCPServerBase",
34
30
  "FlockMCPServerConfig",
35
31
  "FlockMCPToolBase",
36
- "FlockModule",
37
- "FlockModuleConfig",
38
32
  "FlockRegistry",
39
33
  "flock_callable",
40
34
  "flock_component",
@@ -0,0 +1,16 @@
1
+ # src/flock/core/agent/__init__.py
2
+ """Agent components package."""
3
+
4
+ from .flock_agent_components import FlockAgentComponents
5
+ from .flock_agent_execution import FlockAgentExecution
6
+ from .flock_agent_integration import FlockAgentIntegration
7
+ from .flock_agent_lifecycle import FlockAgentLifecycle
8
+ from .flock_agent_serialization import FlockAgentSerialization
9
+
10
+ __all__ = [
11
+ "FlockAgentComponents",
12
+ "FlockAgentExecution",
13
+ "FlockAgentIntegration",
14
+ "FlockAgentLifecycle",
15
+ "FlockAgentSerialization",
16
+ ]
@@ -0,0 +1,104 @@
1
+ """Component management functionality for FlockAgent."""
2
+
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ from flock.core.component.evaluation_component_base import EvaluationComponentBase
6
+ from flock.core.component.routing_component_base import RoutingComponentBase
7
+ from flock.core.component.utility_component_base import UtilityComponentBase
8
+ from flock.core.logging.logging import get_logger
9
+
10
+ if TYPE_CHECKING:
11
+ from flock.core.flock_agent import FlockAgent
12
+ from flock.core.component.agent_component_base import AgentComponent
13
+
14
+ logger = get_logger("agent.components")
15
+
16
+
17
+ class FlockAgentComponents:
18
+ """Helper class for managing unified components on FlockAgent."""
19
+
20
+ def __init__(self, agent: "FlockAgent"):
21
+ self.agent = agent
22
+
23
+ def add_component(self, component: "AgentComponent") -> None:
24
+ """Add a unified component to this agent."""
25
+ if not component.name:
26
+ logger.error("Component must have a name to be added.")
27
+ return
28
+
29
+ # Check if component with same name already exists
30
+ existing = self.get_component(component.name)
31
+ if existing:
32
+ logger.warning(f"Overwriting existing component: {component.name}")
33
+ self.agent.components.remove(existing)
34
+
35
+ self.agent.components.append(component)
36
+ logger.debug(f"Added component '{component.name}' to agent '{self.agent.name}'")
37
+
38
+ def remove_component(self, component_name: str) -> None:
39
+ """Remove a component from this agent."""
40
+ component = self.get_component(component_name)
41
+ if component:
42
+ self.agent.components.remove(component)
43
+ logger.debug(f"Removed component '{component_name}' from agent '{self.agent.name}'")
44
+ else:
45
+ logger.warning(f"Component '{component_name}' not found on agent '{self.agent.name}'")
46
+
47
+ def get_component(self, component_name: str) -> "AgentComponent | None":
48
+ """Get a component by name."""
49
+ for component in self.agent.components:
50
+ if component.name == component_name:
51
+ return component
52
+ return None
53
+
54
+ def get_enabled_components(self) -> list["AgentComponent"]:
55
+ """Get a list of currently enabled components attached to this agent."""
56
+ return [c for c in self.agent.components if c.config.enabled]
57
+
58
+ def get_components_by_type(self, component_type: type) -> list["AgentComponent"]:
59
+ """Get all components of a specific type."""
60
+ return [c for c in self.agent.components if isinstance(c, component_type)]
61
+
62
+ def get_evaluation_components(self) -> list[EvaluationComponentBase]:
63
+ """Get all evaluation components."""
64
+ return self.get_components_by_type(EvaluationComponentBase)
65
+
66
+ def get_routing_components(self) -> list[RoutingComponentBase]:
67
+ """Get all routing components."""
68
+ return self.get_components_by_type(RoutingComponentBase)
69
+
70
+ def get_utility_components(self) -> list[UtilityComponentBase]:
71
+ """Get all utility components."""
72
+ return self.get_components_by_type(UtilityComponentBase)
73
+
74
+ def get_primary_evaluator(self) -> EvaluationComponentBase | None:
75
+ """Get the primary evaluation component (first one found)."""
76
+ evaluators = self.get_evaluation_components()
77
+ return evaluators[0] if evaluators else None
78
+
79
+ def get_primary_router(self) -> RoutingComponentBase | None:
80
+ """Get the primary routing component (first one found)."""
81
+ routers = self.get_routing_components()
82
+ return routers[0] if routers else None
83
+
84
+ # Legacy compatibility methods (delegate to new unified approach)
85
+ def add_module(self, module: Any) -> None:
86
+ """DEPRECATED: Use add_component() instead."""
87
+ logger.warning("add_module is deprecated - use add_component() instead")
88
+ if hasattr(module, 'name'):
89
+ self.add_component(module)
90
+
91
+ def get_module(self, module_name: str) -> Any | None:
92
+ """DEPRECATED: Use get_component() instead."""
93
+ logger.warning("get_module is deprecated - use get_component() instead")
94
+ return self.get_component(module_name)
95
+
96
+ def get_evaluator(self) -> Any | None:
97
+ """DEPRECATED: Use get_primary_evaluator() instead."""
98
+ logger.warning("get_evaluator is deprecated - use get_primary_evaluator() instead")
99
+ return self.get_primary_evaluator()
100
+
101
+ def get_router(self) -> Any | None:
102
+ """DEPRECATED: Use get_primary_router() instead."""
103
+ logger.warning("get_router is deprecated - use get_primary_router() instead")
104
+ return self.get_primary_router()