flock-core 0.4.527__py3-none-any.whl → 0.5.0b0__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 (130) hide show
  1. flock/cli/execute_flock.py +1 -1
  2. flock/cli/manage_agents.py +6 -6
  3. flock/components/__init__.py +30 -0
  4. flock/components/evaluation/__init__.py +9 -0
  5. flock/components/evaluation/declarative_evaluation_component.py +222 -0
  6. flock/components/routing/__init__.py +15 -0
  7. flock/{routers/conditional/conditional_router.py → components/routing/conditional_routing_component.py} +61 -53
  8. flock/components/routing/default_routing_component.py +103 -0
  9. flock/components/routing/llm_routing_component.py +206 -0
  10. flock/components/utility/__init__.py +15 -0
  11. flock/{modules/enterprise_memory/enterprise_memory_module.py → components/utility/memory_utility_component.py} +195 -173
  12. flock/{modules/performance/metrics_module.py → components/utility/metrics_utility_component.py} +110 -95
  13. flock/{modules/output/output_module.py → components/utility/output_utility_component.py} +47 -45
  14. flock/core/__init__.py +26 -18
  15. flock/core/agent/__init__.py +16 -0
  16. flock/core/agent/flock_agent_components.py +104 -0
  17. flock/core/agent/flock_agent_execution.py +101 -0
  18. flock/core/agent/flock_agent_integration.py +206 -0
  19. flock/core/agent/flock_agent_lifecycle.py +177 -0
  20. flock/core/agent/flock_agent_serialization.py +381 -0
  21. flock/core/api/endpoints.py +2 -2
  22. flock/core/api/service.py +2 -2
  23. flock/core/component/__init__.py +15 -0
  24. flock/core/{flock_module.py → component/agent_component_base.py} +136 -34
  25. flock/core/component/evaluation_component.py +56 -0
  26. flock/core/component/routing_component.py +74 -0
  27. flock/core/component/utility_component.py +69 -0
  28. flock/core/config/flock_agent_config.py +49 -2
  29. flock/core/evaluation/utils.py +3 -2
  30. flock/core/execution/batch_executor.py +1 -1
  31. flock/core/execution/evaluation_executor.py +2 -2
  32. flock/core/execution/opik_executor.py +1 -1
  33. flock/core/flock.py +147 -493
  34. flock/core/flock_agent.py +195 -1032
  35. flock/core/flock_factory.py +114 -90
  36. flock/core/flock_scheduler.py +1 -1
  37. flock/core/flock_server_manager.py +8 -8
  38. flock/core/logging/logging.py +1 -0
  39. flock/core/mcp/flock_mcp_server.py +53 -48
  40. flock/core/mcp/{flock_mcp_tool_base.py → flock_mcp_tool.py} +2 -2
  41. flock/core/mcp/mcp_client.py +9 -9
  42. flock/core/mcp/mcp_client_manager.py +9 -9
  43. flock/core/mcp/mcp_config.py +24 -24
  44. flock/core/mixin/dspy_integration.py +5 -5
  45. flock/core/orchestration/__init__.py +18 -0
  46. flock/core/orchestration/flock_batch_processor.py +94 -0
  47. flock/core/orchestration/flock_evaluator.py +113 -0
  48. flock/core/orchestration/flock_execution.py +288 -0
  49. flock/core/orchestration/flock_initialization.py +125 -0
  50. flock/core/orchestration/flock_server_manager.py +67 -0
  51. flock/core/orchestration/flock_web_server.py +117 -0
  52. flock/core/registry/__init__.py +45 -0
  53. flock/core/registry/agent_registry.py +69 -0
  54. flock/core/registry/callable_registry.py +139 -0
  55. flock/core/registry/component_discovery.py +142 -0
  56. flock/core/registry/component_registry.py +64 -0
  57. flock/core/registry/config_mapping.py +64 -0
  58. flock/core/registry/decorators.py +137 -0
  59. flock/core/registry/registry_hub.py +205 -0
  60. flock/core/registry/server_registry.py +57 -0
  61. flock/core/registry/type_registry.py +86 -0
  62. flock/core/serialization/flock_serializer.py +36 -32
  63. flock/core/serialization/serialization_utils.py +28 -25
  64. flock/core/util/hydrator.py +1 -1
  65. flock/core/util/input_resolver.py +29 -2
  66. flock/mcp/servers/sse/flock_sse_server.py +10 -10
  67. flock/mcp/servers/stdio/flock_stdio_server.py +10 -10
  68. flock/mcp/servers/streamable_http/flock_streamable_http_server.py +10 -10
  69. flock/mcp/servers/websockets/flock_websocket_server.py +10 -10
  70. flock/platform/docker_tools.py +3 -3
  71. flock/webapp/app/chat.py +1 -1
  72. flock/webapp/app/main.py +9 -5
  73. flock/webapp/app/services/flock_service.py +1 -1
  74. flock/webapp/app/services/sharing_store.py +1 -0
  75. flock/workflow/activities.py +67 -92
  76. flock/workflow/agent_execution_activity.py +6 -6
  77. flock/workflow/flock_workflow.py +1 -1
  78. flock_core-0.5.0b0.dist-info/METADATA +272 -0
  79. {flock_core-0.4.527.dist-info → flock_core-0.5.0b0.dist-info}/RECORD +82 -95
  80. flock/core/flock_evaluator.py +0 -60
  81. flock/core/flock_registry.py +0 -702
  82. flock/core/flock_router.py +0 -83
  83. flock/evaluators/__init__.py +0 -1
  84. flock/evaluators/declarative/__init__.py +0 -1
  85. flock/evaluators/declarative/declarative_evaluator.py +0 -217
  86. flock/evaluators/memory/memory_evaluator.py +0 -90
  87. flock/evaluators/test/test_case_evaluator.py +0 -38
  88. flock/evaluators/zep/zep_evaluator.py +0 -59
  89. flock/modules/__init__.py +0 -1
  90. flock/modules/assertion/__init__.py +0 -1
  91. flock/modules/assertion/assertion_module.py +0 -286
  92. flock/modules/callback/__init__.py +0 -1
  93. flock/modules/callback/callback_module.py +0 -91
  94. flock/modules/enterprise_memory/README.md +0 -99
  95. flock/modules/mem0/__init__.py +0 -1
  96. flock/modules/mem0/mem0_module.py +0 -126
  97. flock/modules/mem0_async/__init__.py +0 -1
  98. flock/modules/mem0_async/async_mem0_module.py +0 -126
  99. flock/modules/memory/__init__.py +0 -1
  100. flock/modules/memory/memory_module.py +0 -429
  101. flock/modules/memory/memory_parser.py +0 -125
  102. flock/modules/memory/memory_storage.py +0 -736
  103. flock/modules/output/__init__.py +0 -1
  104. flock/modules/performance/__init__.py +0 -1
  105. flock/modules/zep/__init__.py +0 -1
  106. flock/modules/zep/zep_module.py +0 -192
  107. flock/routers/__init__.py +0 -1
  108. flock/routers/agent/__init__.py +0 -1
  109. flock/routers/agent/agent_router.py +0 -236
  110. flock/routers/agent/handoff_agent.py +0 -58
  111. flock/routers/default/__init__.py +0 -1
  112. flock/routers/default/default_router.py +0 -80
  113. flock/routers/feedback/feedback_router.py +0 -114
  114. flock/routers/list_generator/list_generator_router.py +0 -166
  115. flock/routers/llm/__init__.py +0 -1
  116. flock/routers/llm/llm_router.py +0 -365
  117. flock/tools/__init__.py +0 -0
  118. flock/tools/azure_tools.py +0 -781
  119. flock/tools/code_tools.py +0 -167
  120. flock/tools/file_tools.py +0 -149
  121. flock/tools/github_tools.py +0 -157
  122. flock/tools/markdown_tools.py +0 -205
  123. flock/tools/system_tools.py +0 -9
  124. flock/tools/text_tools.py +0 -810
  125. flock/tools/web_tools.py +0 -90
  126. flock/tools/zendesk_tools.py +0 -147
  127. flock_core-0.4.527.dist-info/METADATA +0 -674
  128. {flock_core-0.4.527.dist-info → flock_core-0.5.0b0.dist-info}/WHEEL +0 -0
  129. {flock_core-0.4.527.dist-info → flock_core-0.5.0b0.dist-info}/entry_points.txt +0 -0
  130. {flock_core-0.4.527.dist-info → flock_core-0.5.0b0.dist-info}/licenses/LICENSE +0 -0
@@ -1,21 +1,25 @@
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 import UtilityComponent
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.mcp.flock_mcp_server import FlockMCPServerBase
18
+ from flock.core.mcp.flock_mcp_server import FlockMCPServer
19
+ from flock.core.registry import flock_component
20
+
21
+ if TYPE_CHECKING:
22
+ from flock.core.flock_agent import FlockAgent
19
23
 
20
24
 
21
25
  class MetricPoint(BaseModel):
@@ -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(UtilityComponent):
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
  """
@@ -525,7 +540,7 @@ class MetricsModule(FlockModule):
525
540
 
526
541
  # --- MCP Server Lifecycle Hooks ---
527
542
  async def on_server_error(
528
- self, server: FlockMCPServerBase, error: Exception
543
+ self, server: FlockMCPServer, error: Exception
529
544
  ) -> None:
530
545
  """Record server error metrics."""
531
546
  self._record_metric(
@@ -537,7 +552,7 @@ class MetricsModule(FlockModule):
537
552
  },
538
553
  )
539
554
 
540
- async def on_pre_server_init(self, server: FlockMCPServerBase):
555
+ async def on_pre_server_init(self, server: FlockMCPServer):
541
556
  """Initialize metrics collection for server."""
542
557
  self._server_start_time = time.time()
543
558
 
@@ -549,7 +564,7 @@ class MetricsModule(FlockModule):
549
564
  {"server": server.config.name, "phase": "pre_init"},
550
565
  )
551
566
 
552
- async def on_post_server_init(self, server: FlockMCPServerBase):
567
+ async def on_post_server_init(self, server: FlockMCPServer):
553
568
  """Collect metrics after server starts."""
554
569
  if self.config.collect_memory:
555
570
  checkpoint_memory = psutil.Process().memory_info().rss
@@ -559,7 +574,7 @@ class MetricsModule(FlockModule):
559
574
  {"server": server.config.name, "phase": "post_init"},
560
575
  )
561
576
 
562
- async def on_pre_server_terminate(self, server: FlockMCPServerBase):
577
+ async def on_pre_server_terminate(self, server: FlockMCPServer):
563
578
  """Collect metrics before server terminates."""
564
579
  if self.config.collect_memory:
565
580
  checkpoint_memory = psutil.Process().memory_info().rss
@@ -569,7 +584,7 @@ class MetricsModule(FlockModule):
569
584
  {"server": server.config.name, "phase": "pre_terminate"},
570
585
  )
571
586
 
572
- async def on_post_server_terminate(self, server: FlockMCPServerBase):
587
+ async def on_post_server_terminate(self, server: FlockMCPServer):
573
588
  """Collect metrics after server terminates.
574
589
 
575
590
  Clean up and final metric recording.
@@ -600,7 +615,7 @@ class MetricsModule(FlockModule):
600
615
  json.dump(summary, f, indent=2)
601
616
 
602
617
  async def on_pre_mcp_call(
603
- self, server: FlockMCPServerBase, arguments: Any | None = None
618
+ self, server: FlockMCPServer, arguments: Any | None = None
604
619
  ):
605
620
  """Record pre-call metrics."""
606
621
  if self.config.collect_cpu:
@@ -630,7 +645,7 @@ class MetricsModule(FlockModule):
630
645
  )
631
646
 
632
647
  async def on_post_mcp_call(
633
- self, server: FlockMCPServerBase, result: Any | None = None
648
+ self, server: FlockMCPServer, result: Any | None = None
634
649
  ):
635
650
  """Record post-call metrics."""
636
651
  if self.config.collect_timing and self._server_start_time:
@@ -661,7 +676,7 @@ class MetricsModule(FlockModule):
661
676
  )
662
677
 
663
678
  async def on_connect(
664
- self, server: FlockMCPServerBase, additional_params: dict[str, Any]
679
+ self, server: FlockMCPServer, additional_params: dict[str, Any]
665
680
  ) -> dict[str, Any]:
666
681
  """Collect metrics during connect."""
667
682
  # We should track the refresh rate for clients
@@ -1,31 +1,29 @@
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 import UtilityComponent
13
11
  from flock.core.context.context import FlockContext
14
- from flock.core.flock_module import FlockModule, FlockModuleConfig
12
+ from flock.core.context.context_vars import FLOCK_BATCH_SILENT_MODE
15
13
  from flock.core.logging.formatters.themed_formatter import (
16
14
  ThemedAgentResultFormatter,
17
15
  )
18
16
  from flock.core.logging.formatters.themes import OutputTheme
19
17
  from flock.core.logging.logging import get_logger
18
+ from flock.core.registry import flock_component
20
19
 
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
20
+ if TYPE_CHECKING:
21
+ from flock.core.flock_agent import FlockAgent
24
22
 
25
- logger = get_logger("module.output")
23
+ logger = get_logger("components.utility.output")
26
24
 
27
25
 
28
- class OutputModuleConfig(FlockModuleConfig):
26
+ class OutputUtilityConfig(AgentComponentConfig):
29
27
  """Configuration for output formatting and display."""
30
28
 
31
29
  theme: OutputTheme = Field(
@@ -61,17 +59,18 @@ class OutputModuleConfig(FlockModuleConfig):
61
59
  )
62
60
 
63
61
 
64
- @flock_component(config_class=OutputModuleConfig)
65
- class OutputModule(FlockModule):
66
- """Module that handles output formatting and display."""
62
+ @flock_component(config_class=OutputUtilityConfig)
63
+ class OutputUtilityComponent(UtilityComponent):
64
+ """Utility component that handles output formatting and display."""
67
65
 
68
- name: str = "output"
69
- config: OutputModuleConfig = Field(
70
- default_factory=OutputModuleConfig, description="Output configuration"
66
+ config: OutputUtilityConfig = Field(
67
+ default_factory=OutputUtilityConfig, description="Output configuration"
71
68
  )
72
69
 
73
- def __init__(self, name: str, config: OutputModuleConfig):
74
- super().__init__(name=name, config=config)
70
+ def __init__(self, name: str = "output", config: OutputUtilityConfig | None = None, **data):
71
+ if config is None:
72
+ config = OutputUtilityConfig()
73
+ super().__init__(name=name, config=config, **data)
75
74
  self._formatter = ThemedAgentResultFormatter(
76
75
  theme=self.config.theme,
77
76
  max_length=self.config.max_length,
@@ -98,34 +97,40 @@ class OutputModule(FlockModule):
98
97
 
99
98
  def _format_dict(self, d: dict[str, Any], indent: int = 0) -> str:
100
99
  """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)
100
+ if not d:
101
+ return "{}"
102
+
103
+ items = []
104
+ prefix = " " * indent
105
+ for key, value in d.items():
106
+ if self.config.truncate_long_values and isinstance(value, str) and len(value) > 100:
107
+ value = value[:97] + "..."
108
+ formatted_value = self._format_value(value, key)
109
+ items.append(f"{prefix} {key}: {formatted_value}")
110
+
111
+ return "{\n" + "\n".join(items) + f"\n{prefix}}}"
113
112
 
114
113
  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)
114
+ """Format a list with proper structure."""
115
+ if not lst:
116
+ return "[]"
117
117
 
118
- def _format_potential_code(self, text: str) -> str:
119
- """Format text that might contain code blocks."""
120
- import re
118
+ if len(lst) <= 3:
119
+ return str(lst)
120
+
121
+ # For longer lists, show first few items and count
122
+ preview = [str(item) for item in lst[:3]]
123
+ return f"[{', '.join(preview)}, ... ({len(lst)} total)]"
121
124
 
125
+ def _format_potential_code(self, text: str) -> str:
126
+ """Apply syntax highlighting to potential code blocks."""
127
+ # Simple pattern matching for code blocks
122
128
  def replace_code_block(match):
129
+ language = match.group(1) or "text"
123
130
  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```"
131
+ return f"[CODE:{language}]\n{code}\n[/CODE]"
127
132
 
128
- # Replace code blocks with formatted versions
133
+ # Replace markdown-style code blocks
129
134
  text = re.sub(
130
135
  r"```(\w+)?\n(.*?)\n```", replace_code_block, text, flags=re.DOTALL
131
136
  )
@@ -174,7 +179,6 @@ class OutputModule(FlockModule):
174
179
  theme=self.config.theme,
175
180
  max_length=self.config.max_length,
176
181
  render_table=self.config.render_table,
177
- wait_for_input=self.config.wait_for_input,
178
182
  )
179
183
  self._formatter.display_result(result_to_display, agent.name)
180
184
 
@@ -187,8 +191,6 @@ class OutputModule(FlockModule):
187
191
  theme=self.config.theme,
188
192
  max_length=self.config.max_length,
189
193
  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
194
  )
193
195
 
194
196
  def add_custom_formatter(self, key: str, formatter_name: str) -> None:
flock/core/__init__.py CHANGED
@@ -1,40 +1,48 @@
1
1
  """This module contains the core classes of the flock package."""
2
2
 
3
+ from flock.core.component import (
4
+ AgentComponent,
5
+ AgentComponentConfig,
6
+ EvaluationComponent,
7
+ RoutingComponent,
8
+ UtilityComponent,
9
+ )
3
10
  from flock.core.context.context import FlockContext
4
11
  from flock.core.flock import Flock
5
12
  from flock.core.flock_agent import FlockAgent
6
- from flock.core.flock_evaluator import FlockEvaluator, FlockEvaluatorConfig
7
13
  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,
14
+ from flock.core.mcp.flock_mcp_server import (
15
+ FlockMCPServer,
16
+ )
17
+ from flock.core.mcp.flock_mcp_tool import FlockMCPTool
18
+ from flock.core.mcp.mcp_client import FlockMCPClient
19
+ from flock.core.mcp.mcp_client_manager import FlockMCPClientManager
20
+ from flock.core.registry import (
21
+ RegistryHub as FlockRegistry, # Keep FlockRegistry name for API compatibility
11
22
  flock_callable,
12
23
  flock_component,
13
24
  flock_tool,
14
25
  flock_type,
15
26
  get_registry,
16
27
  )
17
- from flock.core.mcp.flock_mcp_server import (
18
- FlockMCPServerBase,
19
- )
20
- from flock.core.mcp.flock_mcp_tool_base import FlockMCPToolBase
21
- from flock.core.mcp.mcp_client import FlockMCPClientBase
22
- from flock.core.mcp.mcp_client_manager import FlockMCPClientManagerBase
23
28
 
24
29
  __all__ = [
25
30
  "Flock",
26
31
  "FlockAgent",
27
32
  "FlockContext",
28
- "FlockEvaluator",
29
- "FlockEvaluatorConfig",
30
33
  "FlockFactory",
31
- "FlockMCPClientBase",
32
- "FlockMCPClientManagerBase",
33
- "FlockMCPServerBase",
34
+ # Components
35
+ "AgentComponent",
36
+ "AgentComponentConfig",
37
+ "EvaluationComponent",
38
+ "RoutingComponent",
39
+ "UtilityComponent",
40
+
41
+ "FlockMCPClient",
42
+ "FlockMCPClientManager",
43
+ "FlockMCPServer",
34
44
  "FlockMCPServerConfig",
35
- "FlockMCPToolBase",
36
- "FlockModule",
37
- "FlockModuleConfig",
45
+ "FlockMCPTool",
38
46
  "FlockRegistry",
39
47
  "flock_callable",
40
48
  "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
+ ]