flock-core 0.4.528__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.
- flock/cli/execute_flock.py +1 -1
- flock/cli/manage_agents.py +6 -6
- flock/components/__init__.py +30 -0
- flock/components/evaluation/__init__.py +9 -0
- flock/components/evaluation/declarative_evaluation_component.py +222 -0
- flock/components/routing/__init__.py +15 -0
- flock/{routers/conditional/conditional_router.py → components/routing/conditional_routing_component.py} +61 -53
- flock/components/routing/default_routing_component.py +103 -0
- flock/components/routing/llm_routing_component.py +206 -0
- flock/components/utility/__init__.py +15 -0
- flock/{modules/enterprise_memory/enterprise_memory_module.py → components/utility/memory_utility_component.py} +195 -173
- flock/{modules/performance/metrics_module.py → components/utility/metrics_utility_component.py} +110 -95
- flock/{modules/output/output_module.py → components/utility/output_utility_component.py} +47 -45
- flock/core/__init__.py +26 -18
- flock/core/agent/__init__.py +16 -0
- flock/core/agent/flock_agent_components.py +104 -0
- flock/core/agent/flock_agent_execution.py +101 -0
- flock/core/agent/flock_agent_integration.py +206 -0
- flock/core/agent/flock_agent_lifecycle.py +177 -0
- flock/core/agent/flock_agent_serialization.py +381 -0
- flock/core/api/endpoints.py +2 -2
- flock/core/api/service.py +2 -2
- flock/core/component/__init__.py +15 -0
- flock/core/{flock_module.py → component/agent_component_base.py} +136 -34
- flock/core/component/evaluation_component.py +56 -0
- flock/core/component/routing_component.py +74 -0
- flock/core/component/utility_component.py +69 -0
- flock/core/config/flock_agent_config.py +49 -2
- flock/core/evaluation/utils.py +3 -2
- flock/core/execution/batch_executor.py +1 -1
- flock/core/execution/evaluation_executor.py +2 -2
- flock/core/execution/opik_executor.py +1 -1
- flock/core/flock.py +147 -493
- flock/core/flock_agent.py +195 -1032
- flock/core/flock_factory.py +114 -90
- flock/core/flock_scheduler.py +1 -1
- flock/core/flock_server_manager.py +8 -8
- flock/core/logging/logging.py +1 -0
- flock/core/mcp/flock_mcp_server.py +53 -48
- flock/core/mcp/{flock_mcp_tool_base.py → flock_mcp_tool.py} +2 -2
- flock/core/mcp/mcp_client.py +9 -9
- flock/core/mcp/mcp_client_manager.py +9 -9
- flock/core/mcp/mcp_config.py +24 -24
- flock/core/mixin/dspy_integration.py +5 -5
- flock/core/orchestration/__init__.py +18 -0
- flock/core/orchestration/flock_batch_processor.py +94 -0
- flock/core/orchestration/flock_evaluator.py +113 -0
- flock/core/orchestration/flock_execution.py +288 -0
- flock/core/orchestration/flock_initialization.py +125 -0
- flock/core/orchestration/flock_server_manager.py +67 -0
- flock/core/orchestration/flock_web_server.py +117 -0
- flock/core/registry/__init__.py +45 -0
- flock/core/registry/agent_registry.py +69 -0
- flock/core/registry/callable_registry.py +139 -0
- flock/core/registry/component_discovery.py +142 -0
- flock/core/registry/component_registry.py +64 -0
- flock/core/registry/config_mapping.py +64 -0
- flock/core/registry/decorators.py +137 -0
- flock/core/registry/registry_hub.py +205 -0
- flock/core/registry/server_registry.py +57 -0
- flock/core/registry/type_registry.py +86 -0
- flock/core/serialization/flock_serializer.py +36 -32
- flock/core/serialization/serialization_utils.py +28 -25
- flock/core/util/hydrator.py +1 -1
- flock/core/util/input_resolver.py +29 -2
- flock/mcp/servers/sse/flock_sse_server.py +10 -10
- flock/mcp/servers/stdio/flock_stdio_server.py +10 -10
- flock/mcp/servers/streamable_http/flock_streamable_http_server.py +10 -10
- flock/mcp/servers/websockets/flock_websocket_server.py +10 -10
- flock/platform/docker_tools.py +3 -3
- flock/webapp/app/chat.py +1 -1
- flock/webapp/app/main.py +9 -5
- flock/webapp/app/services/flock_service.py +1 -1
- flock/webapp/app/services/sharing_store.py +1 -0
- flock/workflow/activities.py +67 -92
- flock/workflow/agent_execution_activity.py +6 -6
- flock/workflow/flock_workflow.py +1 -1
- flock_core-0.5.0b0.dist-info/METADATA +272 -0
- {flock_core-0.4.528.dist-info → flock_core-0.5.0b0.dist-info}/RECORD +82 -95
- flock/core/flock_evaluator.py +0 -60
- flock/core/flock_registry.py +0 -702
- flock/core/flock_router.py +0 -83
- flock/evaluators/__init__.py +0 -1
- flock/evaluators/declarative/__init__.py +0 -1
- flock/evaluators/declarative/declarative_evaluator.py +0 -217
- flock/evaluators/memory/memory_evaluator.py +0 -90
- flock/evaluators/test/test_case_evaluator.py +0 -38
- flock/evaluators/zep/zep_evaluator.py +0 -59
- flock/modules/__init__.py +0 -1
- flock/modules/assertion/__init__.py +0 -1
- flock/modules/assertion/assertion_module.py +0 -286
- flock/modules/callback/__init__.py +0 -1
- flock/modules/callback/callback_module.py +0 -91
- flock/modules/enterprise_memory/README.md +0 -99
- flock/modules/mem0/__init__.py +0 -1
- flock/modules/mem0/mem0_module.py +0 -126
- flock/modules/mem0_async/__init__.py +0 -1
- flock/modules/mem0_async/async_mem0_module.py +0 -126
- flock/modules/memory/__init__.py +0 -1
- flock/modules/memory/memory_module.py +0 -429
- flock/modules/memory/memory_parser.py +0 -125
- flock/modules/memory/memory_storage.py +0 -736
- flock/modules/output/__init__.py +0 -1
- flock/modules/performance/__init__.py +0 -1
- flock/modules/zep/__init__.py +0 -1
- flock/modules/zep/zep_module.py +0 -192
- flock/routers/__init__.py +0 -1
- flock/routers/agent/__init__.py +0 -1
- flock/routers/agent/agent_router.py +0 -236
- flock/routers/agent/handoff_agent.py +0 -58
- flock/routers/default/__init__.py +0 -1
- flock/routers/default/default_router.py +0 -80
- flock/routers/feedback/feedback_router.py +0 -114
- flock/routers/list_generator/list_generator_router.py +0 -166
- flock/routers/llm/__init__.py +0 -1
- flock/routers/llm/llm_router.py +0 -365
- flock/tools/__init__.py +0 -0
- flock/tools/azure_tools.py +0 -781
- flock/tools/code_tools.py +0 -167
- flock/tools/file_tools.py +0 -149
- flock/tools/github_tools.py +0 -157
- flock/tools/markdown_tools.py +0 -205
- flock/tools/system_tools.py +0 -9
- flock/tools/text_tools.py +0 -810
- flock/tools/web_tools.py +0 -90
- flock/tools/zendesk_tools.py +0 -147
- flock_core-0.4.528.dist-info/METADATA +0 -675
- {flock_core-0.4.528.dist-info → flock_core-0.5.0b0.dist-info}/WHEEL +0 -0
- {flock_core-0.4.528.dist-info → flock_core-0.5.0b0.dist-info}/entry_points.txt +0 -0
- {flock_core-0.4.528.dist-info → flock_core-0.5.0b0.dist-info}/licenses/LICENSE +0 -0
flock/{modules/performance/metrics_module.py → components/utility/metrics_utility_component.py}
RENAMED
|
@@ -1,21 +1,25 @@
|
|
|
1
|
-
|
|
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,
|
|
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.
|
|
16
|
-
from flock.core.
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
29
|
-
arbitrary_types_allowed = True
|
|
32
|
+
model_config = {"arbitrary_types_allowed": True}
|
|
30
33
|
|
|
31
34
|
|
|
32
|
-
class
|
|
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
|
-
@
|
|
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=
|
|
78
|
-
class
|
|
79
|
-
"""
|
|
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: "
|
|
86
|
+
_INSTANCE: "MetricsUtilityComponent | None" = None
|
|
83
87
|
|
|
84
|
-
|
|
85
|
-
|
|
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__(
|
|
91
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
517
|
-
The call will forward to the *first* instantiated
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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.
|
|
8
|
-
from flock.core.
|
|
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.
|
|
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
|
-
|
|
22
|
-
|
|
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("
|
|
23
|
+
logger = get_logger("components.utility.output")
|
|
26
24
|
|
|
27
25
|
|
|
28
|
-
class
|
|
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=
|
|
65
|
-
class
|
|
66
|
-
"""
|
|
62
|
+
@flock_component(config_class=OutputUtilityConfig)
|
|
63
|
+
class OutputUtilityComponent(UtilityComponent):
|
|
64
|
+
"""Utility component that handles output formatting and display."""
|
|
67
65
|
|
|
68
|
-
|
|
69
|
-
|
|
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:
|
|
74
|
-
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
):
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return "\n".join(
|
|
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
|
|
116
|
-
|
|
114
|
+
"""Format a list with proper structure."""
|
|
115
|
+
if not lst:
|
|
116
|
+
return "[]"
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
+
# Components
|
|
35
|
+
"AgentComponent",
|
|
36
|
+
"AgentComponentConfig",
|
|
37
|
+
"EvaluationComponent",
|
|
38
|
+
"RoutingComponent",
|
|
39
|
+
"UtilityComponent",
|
|
40
|
+
|
|
41
|
+
"FlockMCPClient",
|
|
42
|
+
"FlockMCPClientManager",
|
|
43
|
+
"FlockMCPServer",
|
|
34
44
|
"FlockMCPServerConfig",
|
|
35
|
-
"
|
|
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
|
+
]
|