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.
- 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.527.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.527.dist-info/METADATA +0 -674
- {flock_core-0.4.527.dist-info → flock_core-0.5.0b0.dist-info}/WHEEL +0 -0
- {flock_core-0.4.527.dist-info → flock_core-0.5.0b0.dist-info}/entry_points.txt +0 -0
- {flock_core-0.4.527.dist-info → flock_core-0.5.0b0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# src/flock/core/serialization/flock_serializer.py
|
|
2
2
|
"""Handles serialization and deserialization logic for Flock instances."""
|
|
3
3
|
|
|
4
|
-
import builtins
|
|
5
4
|
import importlib
|
|
6
5
|
import importlib.util
|
|
7
6
|
import inspect
|
|
@@ -13,9 +12,10 @@ from typing import TYPE_CHECKING, Any, Literal
|
|
|
13
12
|
|
|
14
13
|
from pydantic import BaseModel, create_model
|
|
15
14
|
|
|
16
|
-
# Need registry access
|
|
17
|
-
from flock.core.flock_registry import get_registry
|
|
18
15
|
from flock.core.logging.logging import get_logger
|
|
16
|
+
|
|
17
|
+
# Need registry access
|
|
18
|
+
from flock.core.registry import get_registry
|
|
19
19
|
from flock.core.serialization.serialization_utils import (
|
|
20
20
|
# Assuming this handles basic serialization needs
|
|
21
21
|
extract_pydantic_models_from_type_string,
|
|
@@ -26,7 +26,7 @@ if TYPE_CHECKING:
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
logger = get_logger("serialization.flock")
|
|
29
|
-
|
|
29
|
+
registry = get_registry()
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
class FlockSerializer:
|
|
@@ -186,7 +186,7 @@ class FlockSerializer:
|
|
|
186
186
|
"description_callable"
|
|
187
187
|
]
|
|
188
188
|
description_callable = agent_instance.description
|
|
189
|
-
path_str =
|
|
189
|
+
path_str = registry.get_callable_path_string(
|
|
190
190
|
description_callable
|
|
191
191
|
)
|
|
192
192
|
if path_str:
|
|
@@ -205,7 +205,7 @@ class FlockSerializer:
|
|
|
205
205
|
)
|
|
206
206
|
input_callable_name = agent_data["input_callable"]
|
|
207
207
|
input_callable = agent_instance.input
|
|
208
|
-
path_str =
|
|
208
|
+
path_str = registry.get_callable_path_string(
|
|
209
209
|
input_callable
|
|
210
210
|
)
|
|
211
211
|
if path_str:
|
|
@@ -224,7 +224,7 @@ class FlockSerializer:
|
|
|
224
224
|
)
|
|
225
225
|
output_callable_name = agent_data["output_callable"]
|
|
226
226
|
output_callable = agent_instance.output
|
|
227
|
-
path_str =
|
|
227
|
+
path_str = registry.get_callable_path_string(
|
|
228
228
|
output_callable
|
|
229
229
|
)
|
|
230
230
|
if path_str:
|
|
@@ -250,7 +250,7 @@ class FlockSerializer:
|
|
|
250
250
|
tool = tool_objs[i]
|
|
251
251
|
if callable(tool) and not isinstance(tool, type):
|
|
252
252
|
path_str = (
|
|
253
|
-
|
|
253
|
+
registry.get_callable_path_string(tool)
|
|
254
254
|
)
|
|
255
255
|
if path_str:
|
|
256
256
|
logger.debug(
|
|
@@ -293,7 +293,7 @@ class FlockSerializer:
|
|
|
293
293
|
from flock.core.flock import Flock # Import the actual class
|
|
294
294
|
from flock.core.flock_agent import FlockAgent as ConcreteFlockAgent
|
|
295
295
|
from flock.core.mcp.flock_mcp_server import (
|
|
296
|
-
|
|
296
|
+
FlockMCPServer as ConcreteFlockMCPServer,
|
|
297
297
|
)
|
|
298
298
|
|
|
299
299
|
logger.debug(
|
|
@@ -415,7 +415,7 @@ class FlockSerializer:
|
|
|
415
415
|
type_definitions = {}
|
|
416
416
|
for type_name in type_names:
|
|
417
417
|
try:
|
|
418
|
-
type_obj =
|
|
418
|
+
type_obj = registry.get_type(
|
|
419
419
|
type_name
|
|
420
420
|
) # Throws KeyError if not found
|
|
421
421
|
type_def = FlockSerializer._extract_type_definition(
|
|
@@ -490,7 +490,7 @@ class FlockSerializer:
|
|
|
490
490
|
"file_path": None,
|
|
491
491
|
}
|
|
492
492
|
try:
|
|
493
|
-
component_class =
|
|
493
|
+
component_class = registry.get_component(
|
|
494
494
|
component_type_name
|
|
495
495
|
) # Raises KeyError if not found
|
|
496
496
|
component_def["module_path"] = getattr(
|
|
@@ -540,7 +540,7 @@ class FlockSerializer:
|
|
|
540
540
|
"file_path": None,
|
|
541
541
|
}
|
|
542
542
|
try:
|
|
543
|
-
func =
|
|
543
|
+
func = registry.get_callable(
|
|
544
544
|
callable_path
|
|
545
545
|
) # Raises KeyError if not found
|
|
546
546
|
callable_def["module_path"] = getattr(func, "__module__", "unknown")
|
|
@@ -596,7 +596,7 @@ class FlockSerializer:
|
|
|
596
596
|
module = importlib.import_module(module_path)
|
|
597
597
|
if hasattr(module, type_name):
|
|
598
598
|
type_obj = getattr(module, type_name)
|
|
599
|
-
|
|
599
|
+
registry.register_type(type_obj, type_name)
|
|
600
600
|
logger.info(
|
|
601
601
|
f"Registered type '{type_name}' from module '{module_path}'"
|
|
602
602
|
)
|
|
@@ -629,7 +629,7 @@ class FlockSerializer:
|
|
|
629
629
|
type_name: str, type_def: dict[str, Any]
|
|
630
630
|
) -> None:
|
|
631
631
|
"""Dynamically create and register a Pydantic model from schema."""
|
|
632
|
-
# (Logic remains the same, ensure it uses
|
|
632
|
+
# (Logic remains the same, ensure it uses registry.register_type)
|
|
633
633
|
schema = type_def.get("schema", {})
|
|
634
634
|
try:
|
|
635
635
|
fields = {}
|
|
@@ -641,7 +641,7 @@ class FlockSerializer:
|
|
|
641
641
|
fields[field_name] = (field_type, default)
|
|
642
642
|
|
|
643
643
|
DynamicModel = create_model(type_name, **fields)
|
|
644
|
-
|
|
644
|
+
registry.register_type(DynamicModel, type_name)
|
|
645
645
|
logger.info(
|
|
646
646
|
f"Dynamically created and registered Pydantic model: {type_name}"
|
|
647
647
|
)
|
|
@@ -672,27 +672,31 @@ class FlockSerializer:
|
|
|
672
672
|
@staticmethod
|
|
673
673
|
def _create_dataclass(type_name: str, type_def: dict[str, Any]) -> None:
|
|
674
674
|
"""Dynamically create and register a dataclass."""
|
|
675
|
-
# (Logic remains the same, ensure it uses
|
|
675
|
+
# (Logic remains the same, ensure it uses registry.register_type)
|
|
676
676
|
from dataclasses import make_dataclass
|
|
677
677
|
|
|
678
678
|
fields_def = type_def.get("fields", {})
|
|
679
679
|
try:
|
|
680
680
|
fields = []
|
|
681
681
|
for field_name, field_props in fields_def.items():
|
|
682
|
-
# Safely
|
|
682
|
+
# Safely map type strings to actual types
|
|
683
683
|
field_type_str = field_props.get("type", "str")
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
684
|
+
type_mapping = {
|
|
685
|
+
"str": str,
|
|
686
|
+
"int": int,
|
|
687
|
+
"float": float,
|
|
688
|
+
"bool": bool,
|
|
689
|
+
"list": list,
|
|
690
|
+
"dict": dict,
|
|
691
|
+
"List": list,
|
|
692
|
+
"Dict": dict,
|
|
693
|
+
"Any": Any,
|
|
694
|
+
}
|
|
695
|
+
field_type = type_mapping.get(field_type_str, Any)
|
|
692
696
|
fields.append((field_name, field_type))
|
|
693
697
|
|
|
694
698
|
DynamicDataclass = make_dataclass(type_name, fields)
|
|
695
|
-
|
|
699
|
+
registry.register_type(DynamicDataclass, type_name)
|
|
696
700
|
logger.info(
|
|
697
701
|
f"Dynamically created and registered dataclass: {type_name}"
|
|
698
702
|
)
|
|
@@ -705,7 +709,7 @@ class FlockSerializer:
|
|
|
705
709
|
path_type: Literal["absolute", "relative"],
|
|
706
710
|
) -> None:
|
|
707
711
|
"""Register component/callable definitions from serialized data."""
|
|
708
|
-
# (Logic remains the same, ensure it uses
|
|
712
|
+
# (Logic remains the same, ensure it uses registry.register_component/register_callable)
|
|
709
713
|
# Key change: Ensure file_path is handled correctly based on path_type from metadata
|
|
710
714
|
for name, comp_def in component_defs.items():
|
|
711
715
|
logger.debug(
|
|
@@ -735,13 +739,13 @@ class FlockSerializer:
|
|
|
735
739
|
if hasattr(module, name):
|
|
736
740
|
obj = getattr(module, name)
|
|
737
741
|
if kind == "flock_callable" and callable(obj):
|
|
738
|
-
|
|
742
|
+
registry.register_callable(
|
|
739
743
|
obj, name
|
|
740
744
|
) # Register by simple name
|
|
741
745
|
# Also register by full path if possible
|
|
742
746
|
full_path = f"{module_path}.{name}"
|
|
743
747
|
if full_path != name:
|
|
744
|
-
|
|
748
|
+
registry.register_callable(obj, full_path)
|
|
745
749
|
logger.info(
|
|
746
750
|
f"Registered callable '{name}' from module '{module_path}'"
|
|
747
751
|
)
|
|
@@ -749,7 +753,7 @@ class FlockSerializer:
|
|
|
749
753
|
elif kind == "flock_component" and isinstance(
|
|
750
754
|
obj, type
|
|
751
755
|
):
|
|
752
|
-
|
|
756
|
+
registry.register_component(obj, name)
|
|
753
757
|
logger.info(
|
|
754
758
|
f"Registered component '{name}' from module '{module_path}'"
|
|
755
759
|
)
|
|
@@ -785,14 +789,14 @@ class FlockSerializer:
|
|
|
785
789
|
if hasattr(module, name):
|
|
786
790
|
obj = getattr(module, name)
|
|
787
791
|
if kind == "flock_callable" and callable(obj):
|
|
788
|
-
|
|
792
|
+
registry.register_callable(obj, name)
|
|
789
793
|
logger.info(
|
|
790
794
|
f"Registered callable '{name}' from file '{file_path}'"
|
|
791
795
|
)
|
|
792
796
|
elif kind == "flock_component" and isinstance(
|
|
793
797
|
obj, type
|
|
794
798
|
):
|
|
795
|
-
|
|
799
|
+
registry.register_component(obj, name)
|
|
796
800
|
logger.info(
|
|
797
801
|
f"Registered component '{name}' from file '{file_path}'"
|
|
798
802
|
)
|
|
@@ -24,13 +24,13 @@ from pydantic import BaseModel
|
|
|
24
24
|
if TYPE_CHECKING:
|
|
25
25
|
pass
|
|
26
26
|
|
|
27
|
-
from flock.core.
|
|
27
|
+
from flock.core.registry import get_registry
|
|
28
28
|
from flock.core.logging.logging import get_logger
|
|
29
29
|
|
|
30
30
|
logger = get_logger("serialization.utils")
|
|
31
31
|
|
|
32
32
|
# Remove this line to avoid circular import at module level
|
|
33
|
-
#
|
|
33
|
+
# registry = get_registry() # Get singleton instance
|
|
34
34
|
|
|
35
35
|
# --- Serialization Helper ---
|
|
36
36
|
|
|
@@ -188,16 +188,16 @@ def collect_pydantic_models(
|
|
|
188
188
|
|
|
189
189
|
def serialize_item(item: Any) -> Any:
|
|
190
190
|
"""Recursively prepares an item for serialization (e.g., to dict for YAML/JSON).
|
|
191
|
-
Converts known callables to their path strings using
|
|
191
|
+
Converts known callables to their path strings using registry.
|
|
192
192
|
Converts Pydantic models using model_dump.
|
|
193
193
|
"""
|
|
194
194
|
# Import the registry lazily when needed
|
|
195
|
-
from flock.core.
|
|
195
|
+
from flock.core.registry import get_registry
|
|
196
196
|
|
|
197
|
-
|
|
197
|
+
registry = get_registry()
|
|
198
198
|
|
|
199
199
|
if callable(item) and not isinstance(item, type):
|
|
200
|
-
path_str =
|
|
200
|
+
path_str = registry.get_callable_path_string(
|
|
201
201
|
item
|
|
202
202
|
) # Use registry helper
|
|
203
203
|
if path_str:
|
|
@@ -248,12 +248,12 @@ def serialize_item(item: Any) -> Any:
|
|
|
248
248
|
elif isinstance(
|
|
249
249
|
item, type
|
|
250
250
|
): # Handle type objects themselves (e.g. if stored directly)
|
|
251
|
-
type_name =
|
|
251
|
+
type_name = registry.get_component_type_name(
|
|
252
252
|
item
|
|
253
253
|
) # Check components first
|
|
254
254
|
if type_name:
|
|
255
255
|
return {"__component_ref__": type_name}
|
|
256
|
-
type_name =
|
|
256
|
+
type_name = registry._get_path_string(
|
|
257
257
|
item
|
|
258
258
|
) # Check regular types/classes by path
|
|
259
259
|
if type_name:
|
|
@@ -274,13 +274,13 @@ def serialize_item(item: Any) -> Any:
|
|
|
274
274
|
|
|
275
275
|
def deserialize_item(item: Any) -> Any:
|
|
276
276
|
"""Recursively processes a deserialized item (e.g., from YAML/JSON dict).
|
|
277
|
-
Converts reference dicts back to actual callables or types using
|
|
277
|
+
Converts reference dicts back to actual callables or types using registry.
|
|
278
278
|
Handles nested lists and dicts.
|
|
279
279
|
"""
|
|
280
280
|
# Import the registry lazily when needed
|
|
281
|
-
from flock.core.
|
|
281
|
+
from flock.core.registry import get_registry
|
|
282
282
|
|
|
283
|
-
|
|
283
|
+
registry = get_registry()
|
|
284
284
|
|
|
285
285
|
if isinstance(item, Mapping):
|
|
286
286
|
if "__callable_ref__" in item and len(item) == 1:
|
|
@@ -288,7 +288,7 @@ def deserialize_item(item: Any) -> Any:
|
|
|
288
288
|
try:
|
|
289
289
|
# The registry's get_callable needs to handle lookup by simple name OR full path
|
|
290
290
|
# Or we assume get_callable handles finding the right function from the simple name
|
|
291
|
-
resolved_callable =
|
|
291
|
+
resolved_callable = registry.get_callable(ref_name)
|
|
292
292
|
logger.debug(
|
|
293
293
|
f"Deserialized callable reference '{ref_name}' to {resolved_callable}"
|
|
294
294
|
)
|
|
@@ -307,7 +307,7 @@ def deserialize_item(item: Any) -> Any:
|
|
|
307
307
|
elif "__component_ref__" in item and len(item) == 1:
|
|
308
308
|
type_name = item["__component_ref__"]
|
|
309
309
|
try:
|
|
310
|
-
return
|
|
310
|
+
return registry.get_component(type_name)
|
|
311
311
|
except KeyError:
|
|
312
312
|
logger.error(
|
|
313
313
|
f"Component reference '{type_name}' not found during deserialization."
|
|
@@ -318,7 +318,7 @@ def deserialize_item(item: Any) -> Any:
|
|
|
318
318
|
try:
|
|
319
319
|
# For general types, use get_type or fallback to dynamic import like get_callable
|
|
320
320
|
# Using get_type for now, assuming it needs registration
|
|
321
|
-
return
|
|
321
|
+
return registry.get_type(type_name)
|
|
322
322
|
except KeyError:
|
|
323
323
|
# Attempt dynamic import as fallback if get_type fails (similar to get_callable)
|
|
324
324
|
try:
|
|
@@ -329,7 +329,7 @@ def deserialize_item(item: Any) -> Any:
|
|
|
329
329
|
mod = importlib.import_module(module_name)
|
|
330
330
|
type_obj = getattr(mod, class_name)
|
|
331
331
|
if isinstance(type_obj, type):
|
|
332
|
-
|
|
332
|
+
registry.register_type(
|
|
333
333
|
type_obj, type_name
|
|
334
334
|
) # Cache it
|
|
335
335
|
return type_obj
|
|
@@ -356,12 +356,12 @@ def deserialize_component(
|
|
|
356
356
|
data: dict | None, expected_base_type: type
|
|
357
357
|
) -> Any | None:
|
|
358
358
|
"""Deserializes a component (Module, Evaluator, Router) from its dict representation.
|
|
359
|
-
Uses the 'type' field to find the correct class via
|
|
359
|
+
Uses the 'type' field to find the correct class via registry.
|
|
360
360
|
"""
|
|
361
361
|
# Import the registry and COMPONENT_BASE_TYPES lazily when needed
|
|
362
|
-
from flock.core.
|
|
362
|
+
from flock.core.registry import get_registry
|
|
363
363
|
|
|
364
|
-
|
|
364
|
+
registry = get_registry()
|
|
365
365
|
|
|
366
366
|
if data is None:
|
|
367
367
|
return None
|
|
@@ -379,14 +379,17 @@ def deserialize_component(
|
|
|
379
379
|
return None
|
|
380
380
|
|
|
381
381
|
try:
|
|
382
|
-
ComponentClass =
|
|
382
|
+
ComponentClass = registry.get_component(type_name) # Use registry
|
|
383
383
|
# Optional: Keep the base type check
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
384
|
+
try:
|
|
385
|
+
from flock.core.component.agent_component_base import AgentComponent
|
|
386
|
+
if not issubclass(ComponentClass, AgentComponent):
|
|
387
|
+
logger.warning(
|
|
388
|
+
f"Deserialized class '{type_name}' is not a subclass of AgentComponent."
|
|
389
|
+
)
|
|
390
|
+
except ImportError:
|
|
391
|
+
# AgentComponent not available during setup
|
|
392
|
+
pass
|
|
390
393
|
|
|
391
394
|
# Recursively deserialize the data *before* passing to Pydantic constructor
|
|
392
395
|
# This handles nested callables/types within the component's config/data
|
flock/core/util/hydrator.py
CHANGED
|
@@ -45,7 +45,12 @@ def top_level_to_keys(s: str) -> list[str]:
|
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
def resolve_inputs(
|
|
48
|
-
input_spec: str,
|
|
48
|
+
input_spec: str,
|
|
49
|
+
context: FlockContext,
|
|
50
|
+
previous_agent_name: str,
|
|
51
|
+
previous_agent_output:str,
|
|
52
|
+
previous_agent_handoff_strategy:str,
|
|
53
|
+
previous_agent_handoff_map:dict[str, str]
|
|
49
54
|
) -> dict:
|
|
50
55
|
"""Build a dictionary of inputs based on the input specification string and the provided context.
|
|
51
56
|
|
|
@@ -63,6 +68,28 @@ def resolve_inputs(
|
|
|
63
68
|
eg. agent name: "idea_agent", variable: "ia_idea" (ia = idea agent)
|
|
64
69
|
- or set hand off mode to strict to avoid conflicts.
|
|
65
70
|
with strict mode, the agent will only accept inputs from the previous agent.
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
Strategy for passing data to the next agent.
|
|
74
|
+
|
|
75
|
+
Example:
|
|
76
|
+
ReviewAgent.next_agent = SummaryAgent
|
|
77
|
+
ReviewAgent(output = "text:str, keywords:list[str], rating:int")
|
|
78
|
+
SummaryAgent(input = "text:str, title:str")
|
|
79
|
+
|
|
80
|
+
'append' means the difference in signature is appended to the next agent's input signature.
|
|
81
|
+
SummaryAgent(input = "text:str, title:str, keywords:list[str], rating:int")
|
|
82
|
+
|
|
83
|
+
'override' means the target agent's signature is getting overriden.
|
|
84
|
+
SummaryAgent(input = "text:str, keywords:list[str], rating:int")
|
|
85
|
+
|
|
86
|
+
'static' means the the target agent's signature is not changed at all.
|
|
87
|
+
If source agent has no output fields that match the target agent's input,
|
|
88
|
+
there will be no data passed to the next agent.
|
|
89
|
+
SummaryAgent(input = "text:str, title:str")
|
|
90
|
+
|
|
91
|
+
'map' means the source agent's output is mapped to the target agent's input
|
|
92
|
+
based on 'handoff_map' configuration.
|
|
66
93
|
|
|
67
94
|
Args:
|
|
68
95
|
input_spec: Comma-separated input keys (e.g., "query" or "agent_name.property").
|
|
@@ -120,7 +147,7 @@ def resolve_inputs(
|
|
|
120
147
|
inputs[key] = context.get_agent_definition(property_name)
|
|
121
148
|
continue
|
|
122
149
|
|
|
123
|
-
# Otherwise, attempt to look up a state variable with the key "
|
|
150
|
+
# Otherwise, attempt to look up a state variable with the key "entity_name.property_name"
|
|
124
151
|
inputs[key] = context.get_variable(f"{entity_name}.{property_name}")
|
|
125
152
|
continue
|
|
126
153
|
|
|
@@ -15,12 +15,12 @@ from opentelemetry import trace
|
|
|
15
15
|
from pydantic import Field
|
|
16
16
|
|
|
17
17
|
from flock.core.logging.logging import get_logger
|
|
18
|
-
from flock.core.mcp.flock_mcp_server import
|
|
19
|
-
from flock.core.mcp.mcp_client import
|
|
20
|
-
from flock.core.mcp.mcp_client_manager import
|
|
18
|
+
from flock.core.mcp.flock_mcp_server import FlockMCPServer
|
|
19
|
+
from flock.core.mcp.mcp_client import FlockMCPClient
|
|
20
|
+
from flock.core.mcp.mcp_client_manager import FlockMCPClientManager
|
|
21
21
|
from flock.core.mcp.mcp_config import (
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
FlockMCPConfiguration,
|
|
23
|
+
FlockMCPConnectionConfiguration,
|
|
24
24
|
)
|
|
25
25
|
from flock.core.mcp.types.types import SseServerParameters
|
|
26
26
|
|
|
@@ -28,7 +28,7 @@ logger = get_logger("mcp.sse.server")
|
|
|
28
28
|
tracer = trace.get_tracer(__name__)
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
class FlockSSEConnectionConfig(
|
|
31
|
+
class FlockSSEConnectionConfig(FlockMCPConnectionConfiguration):
|
|
32
32
|
"""Concrete ConnectionConfig for an SSEClient."""
|
|
33
33
|
|
|
34
34
|
# Only thing we need to override here is the concrete transport_type
|
|
@@ -42,7 +42,7 @@ class FlockSSEConnectionConfig(FlockMCPConnectionConfigurationBase):
|
|
|
42
42
|
)
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
class FlockSSEConfig(
|
|
45
|
+
class FlockSSEConfig(FlockMCPConfiguration):
|
|
46
46
|
"""Configuration for SSE Clients."""
|
|
47
47
|
|
|
48
48
|
# The only thing we need to override here is the concrete
|
|
@@ -53,7 +53,7 @@ class FlockSSEConfig(FlockMCPConfigurationBase):
|
|
|
53
53
|
)
|
|
54
54
|
|
|
55
55
|
|
|
56
|
-
class FlockSSEClient(
|
|
56
|
+
class FlockSSEClient(FlockMCPClient):
|
|
57
57
|
"""Client for SSE Servers."""
|
|
58
58
|
|
|
59
59
|
config: FlockSSEConfig = Field(..., description="Client configuration.")
|
|
@@ -115,7 +115,7 @@ class FlockSSEClient(FlockMCPClientBase):
|
|
|
115
115
|
)
|
|
116
116
|
|
|
117
117
|
|
|
118
|
-
class FlockSSEClientManager(
|
|
118
|
+
class FlockSSEClientManager(FlockMCPClientManager):
|
|
119
119
|
"""Manager for handling SSE Clients."""
|
|
120
120
|
|
|
121
121
|
client_config: FlockSSEConfig = Field(
|
|
@@ -132,7 +132,7 @@ class FlockSSEClientManager(FlockMCPClientManagerBase):
|
|
|
132
132
|
return new_client
|
|
133
133
|
|
|
134
134
|
|
|
135
|
-
class FlockSSEServer(
|
|
135
|
+
class FlockSSEServer(FlockMCPServer):
|
|
136
136
|
"""Class which represents a MCP Server using the SSE Transport type."""
|
|
137
137
|
|
|
138
138
|
config: FlockSSEConfig = Field(..., description="Config for the server.")
|
|
@@ -14,12 +14,12 @@ from opentelemetry import trace
|
|
|
14
14
|
from pydantic import Field
|
|
15
15
|
|
|
16
16
|
from flock.core.logging.logging import get_logger
|
|
17
|
-
from flock.core.mcp.flock_mcp_server import
|
|
18
|
-
from flock.core.mcp.mcp_client import
|
|
19
|
-
from flock.core.mcp.mcp_client_manager import
|
|
17
|
+
from flock.core.mcp.flock_mcp_server import FlockMCPServer
|
|
18
|
+
from flock.core.mcp.mcp_client import FlockMCPClient
|
|
19
|
+
from flock.core.mcp.mcp_client_manager import FlockMCPClientManager
|
|
20
20
|
from flock.core.mcp.mcp_config import (
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
FlockMCPConfiguration,
|
|
22
|
+
FlockMCPConnectionConfiguration,
|
|
23
23
|
)
|
|
24
24
|
from flock.core.mcp.types.types import StdioServerParameters
|
|
25
25
|
|
|
@@ -27,7 +27,7 @@ logger = get_logger("mcp.stdio.server")
|
|
|
27
27
|
tracer = trace.get_tracer(__name__)
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
class FlockStdioConnectionConfig(
|
|
30
|
+
class FlockStdioConnectionConfig(FlockMCPConnectionConfiguration):
|
|
31
31
|
"""Concrete ConnectionConfig for an StdioClient."""
|
|
32
32
|
|
|
33
33
|
# Only thing we need to override here is the concrete transport_type
|
|
@@ -42,7 +42,7 @@ class FlockStdioConnectionConfig(FlockMCPConnectionConfigurationBase):
|
|
|
42
42
|
)
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
class FlockStdioConfig(
|
|
45
|
+
class FlockStdioConfig(FlockMCPConfiguration):
|
|
46
46
|
"""Configuration for Stdio Clients."""
|
|
47
47
|
|
|
48
48
|
# The only thing we need to override here is the
|
|
@@ -53,7 +53,7 @@ class FlockStdioConfig(FlockMCPConfigurationBase):
|
|
|
53
53
|
)
|
|
54
54
|
|
|
55
55
|
|
|
56
|
-
class FlockStdioClient(
|
|
56
|
+
class FlockStdioClient(FlockMCPClient):
|
|
57
57
|
"""Client for Stdio Servers."""
|
|
58
58
|
|
|
59
59
|
config: FlockStdioConfig = Field(..., description="Client Configuration.")
|
|
@@ -104,7 +104,7 @@ class FlockStdioClient(FlockMCPClientBase):
|
|
|
104
104
|
|
|
105
105
|
|
|
106
106
|
# Not really needed but kept here as an example.
|
|
107
|
-
class FlockStdioClientManager(
|
|
107
|
+
class FlockStdioClientManager(FlockMCPClientManager):
|
|
108
108
|
"""Manager for handling Stdio Clients."""
|
|
109
109
|
|
|
110
110
|
client_config: FlockStdioConfig = Field(
|
|
@@ -122,7 +122,7 @@ class FlockStdioClientManager(FlockMCPClientManagerBase):
|
|
|
122
122
|
return new_client
|
|
123
123
|
|
|
124
124
|
|
|
125
|
-
class FlockMCPStdioServer(
|
|
125
|
+
class FlockMCPStdioServer(FlockMCPServer):
|
|
126
126
|
"""Class which represents a MCP Server using the Stdio Transport type.
|
|
127
127
|
|
|
128
128
|
This means (most likely) that the server is a locally
|
|
@@ -17,12 +17,12 @@ from opentelemetry import trace
|
|
|
17
17
|
from pydantic import Field
|
|
18
18
|
|
|
19
19
|
from flock.core.logging.logging import get_logger
|
|
20
|
-
from flock.core.mcp.flock_mcp_server import
|
|
21
|
-
from flock.core.mcp.mcp_client import
|
|
22
|
-
from flock.core.mcp.mcp_client_manager import
|
|
20
|
+
from flock.core.mcp.flock_mcp_server import FlockMCPServer
|
|
21
|
+
from flock.core.mcp.mcp_client import FlockMCPClient
|
|
22
|
+
from flock.core.mcp.mcp_client_manager import FlockMCPClientManager
|
|
23
23
|
from flock.core.mcp.mcp_config import (
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
FlockMCPConfiguration,
|
|
25
|
+
FlockMCPConnectionConfiguration,
|
|
26
26
|
)
|
|
27
27
|
from flock.core.mcp.types.types import (
|
|
28
28
|
StreamableHttpServerParameters,
|
|
@@ -34,7 +34,7 @@ tracer = trace.get_tracer(__name__)
|
|
|
34
34
|
GetSessionIdCallback = Callable[[], str | None]
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
class FlockStreamableHttpConnectionConfig(
|
|
37
|
+
class FlockStreamableHttpConnectionConfig(FlockMCPConnectionConfiguration):
|
|
38
38
|
"""Concrete ConnectionConfig for a StreamableHttpClient."""
|
|
39
39
|
|
|
40
40
|
# Only thing we need to override here is the concrete transport_type
|
|
@@ -49,7 +49,7 @@ class FlockStreamableHttpConnectionConfig(FlockMCPConnectionConfigurationBase):
|
|
|
49
49
|
)
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
class FlockStreamableHttpConfig(
|
|
52
|
+
class FlockStreamableHttpConfig(FlockMCPConfiguration):
|
|
53
53
|
"""Configuration for Streamable HTTP Clients."""
|
|
54
54
|
|
|
55
55
|
# The only thing we need to override here is the
|
|
@@ -60,7 +60,7 @@ class FlockStreamableHttpConfig(FlockMCPConfigurationBase):
|
|
|
60
60
|
)
|
|
61
61
|
|
|
62
62
|
|
|
63
|
-
class FlockStreamableHttpClient(
|
|
63
|
+
class FlockStreamableHttpClient(FlockMCPClient):
|
|
64
64
|
"""Client for StreamableHttpServers."""
|
|
65
65
|
|
|
66
66
|
config: FlockStreamableHttpConfig = Field(
|
|
@@ -135,7 +135,7 @@ class FlockStreamableHttpClient(FlockMCPClientBase):
|
|
|
135
135
|
)
|
|
136
136
|
|
|
137
137
|
|
|
138
|
-
class FlockStreamableHttpClientManager(
|
|
138
|
+
class FlockStreamableHttpClientManager(FlockMCPClientManager):
|
|
139
139
|
"""Manager for handling StreamableHttpClients."""
|
|
140
140
|
|
|
141
141
|
client_config: FlockStreamableHttpConfig = Field(
|
|
@@ -153,7 +153,7 @@ class FlockStreamableHttpClientManager(FlockMCPClientManagerBase):
|
|
|
153
153
|
return new_client
|
|
154
154
|
|
|
155
155
|
|
|
156
|
-
class FlockStreamableHttpServer(
|
|
156
|
+
class FlockStreamableHttpServer(FlockMCPServer):
|
|
157
157
|
"""Class which represents a MCP Server using the streamable Http Transport type."""
|
|
158
158
|
|
|
159
159
|
config: FlockStreamableHttpConfig = Field(
|
|
@@ -14,12 +14,12 @@ from opentelemetry import trace
|
|
|
14
14
|
from pydantic import Field
|
|
15
15
|
|
|
16
16
|
from flock.core.logging.logging import get_logger
|
|
17
|
-
from flock.core.mcp.flock_mcp_server import
|
|
18
|
-
from flock.core.mcp.mcp_client import
|
|
19
|
-
from flock.core.mcp.mcp_client_manager import
|
|
17
|
+
from flock.core.mcp.flock_mcp_server import FlockMCPServer
|
|
18
|
+
from flock.core.mcp.mcp_client import FlockMCPClient
|
|
19
|
+
from flock.core.mcp.mcp_client_manager import FlockMCPClientManager
|
|
20
20
|
from flock.core.mcp.mcp_config import (
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
FlockMCPConfiguration,
|
|
22
|
+
FlockMCPConnectionConfiguration,
|
|
23
23
|
)
|
|
24
24
|
from flock.core.mcp.types.types import WebsocketServerParameters
|
|
25
25
|
|
|
@@ -28,7 +28,7 @@ tracer = trace.get_tracer(__name__)
|
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
# Optional to provide type hints.
|
|
31
|
-
class FlockWSConnectionConfig(
|
|
31
|
+
class FlockWSConnectionConfig(FlockMCPConnectionConfiguration):
|
|
32
32
|
"""Concrete ConnectionConfig for a WS Client."""
|
|
33
33
|
|
|
34
34
|
# Only thing we need to override here is the concrete transport_type
|
|
@@ -44,7 +44,7 @@ class FlockWSConnectionConfig(FlockMCPConnectionConfigurationBase):
|
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
# Optional to provide type hints.
|
|
47
|
-
class FlockWSConfig(
|
|
47
|
+
class FlockWSConfig(FlockMCPConfiguration):
|
|
48
48
|
"""Configuration for Websocket clients."""
|
|
49
49
|
|
|
50
50
|
# The only thing we need to override here is the concrete
|
|
@@ -56,7 +56,7 @@ class FlockWSConfig(FlockMCPConfigurationBase):
|
|
|
56
56
|
)
|
|
57
57
|
|
|
58
58
|
|
|
59
|
-
class FlockWSClient(
|
|
59
|
+
class FlockWSClient(FlockMCPClient):
|
|
60
60
|
"""Client for Websocket servers."""
|
|
61
61
|
|
|
62
62
|
config: FlockWSConfig = Field(..., description="Client Configuration")
|
|
@@ -90,7 +90,7 @@ class FlockWSClient(FlockMCPClientBase):
|
|
|
90
90
|
|
|
91
91
|
|
|
92
92
|
# not really needed, but kept for type hints and as an example.
|
|
93
|
-
class FlockWSClientManager(
|
|
93
|
+
class FlockWSClientManager(FlockMCPClientManager):
|
|
94
94
|
"""Manager for handling websocket clients."""
|
|
95
95
|
|
|
96
96
|
client_config: FlockWSConfig = Field(
|
|
@@ -106,7 +106,7 @@ class FlockWSClientManager(FlockMCPClientManagerBase):
|
|
|
106
106
|
return new_client
|
|
107
107
|
|
|
108
108
|
|
|
109
|
-
class FlockWSServer(
|
|
109
|
+
class FlockWSServer(FlockMCPServer):
|
|
110
110
|
"""Class which represents an MCP Server using the websocket transport type."""
|
|
111
111
|
|
|
112
112
|
config: FlockWSConfig = Field(..., description="Config for the server.")
|