flock-core 0.3.5__py3-none-any.whl → 0.3.8__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/assets/release_notes.md +37 -9
- flock/core/context/context.py +1 -1
- flock/core/flock_agent.py +5 -23
- flock/core/flock_factory.py +8 -5
- flock/core/flock_module.py +3 -1
- flock/core/flock_router.py +70 -0
- flock/core/serialization/secure_serializer.py +175 -0
- flock/evaluators/zep/zep_evaluator.py +2 -0
- flock/routers/__init__.py +1 -0
- flock/routers/agent/__init__.py +1 -0
- flock/routers/agent/agent_router.py +234 -0
- flock/routers/agent/handoff_agent.py +58 -0
- flock/routers/default/__init__.py +1 -0
- flock/routers/default/default_router.py +76 -0
- flock/routers/llm/__init__.py +1 -0
- flock/routers/llm/llm_router.py +363 -0
- flock/workflow/activities.py +74 -33
- {flock_core-0.3.5.dist-info → flock_core-0.3.8.dist-info}/METADATA +1 -1
- {flock_core-0.3.5.dist-info → flock_core-0.3.8.dist-info}/RECORD +23 -13
- /flock/core/{util → serialization}/serializable.py +0 -0
- {flock_core-0.3.5.dist-info → flock_core-0.3.8.dist-info}/WHEEL +0 -0
- {flock_core-0.3.5.dist-info → flock_core-0.3.8.dist-info}/entry_points.txt +0 -0
- {flock_core-0.3.5.dist-info → flock_core-0.3.8.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
# Flock v0.3 - Hummingbird
|
|
3
2
|
|
|
4
3
|
We're excited to announce Flock v0.3, codenamed **"Hummingbird"**! This release brings a fundamental redesign of Flock's core architecture, introducing **unprecedented modularity and flexibility** to AI agent development.
|
|
@@ -13,17 +12,17 @@ Like a hummingbird, modules are small and nimble code packages. Put enough of th
|
|
|
13
12
|
|
|
14
13
|
### Other notable additions:
|
|
15
14
|
- **CLI Interface** – Flock now has a command-line interface
|
|
15
|
+
- **REST API Server** – Expose your agents via HTTP endpoints
|
|
16
16
|
- **Color-coded logging** – Better debugging experience
|
|
17
17
|
- **New examples**
|
|
18
18
|
- ...and much more!
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
-
## Core Changes
|
|
22
|
+
## Core Changes
|
|
23
23
|
|
|
24
|
-
### New Module System
|
|
25
|
-
- **
|
|
26
|
-
- Simple yet powerful lifecycle hooks: `initialize`, `pre_evaluate`, `post_evaluate`, `terminate`
|
|
24
|
+
### New Module System
|
|
25
|
+
- **Pluggable modules system á la FastAPI**
|
|
27
26
|
- **Easy-to-implement** module interface
|
|
28
27
|
- **Configuration system** for clean parameter management
|
|
29
28
|
|
|
@@ -32,15 +31,44 @@ Like a hummingbird, modules are small and nimble code packages. Put enough of th
|
|
|
32
31
|
- Built-in support for multiple evaluation strategies:
|
|
33
32
|
- **Declarative Evaluator** – The default way Flock is designed
|
|
34
33
|
- **Natural Language Evaluator** – Use "classic" prompting
|
|
34
|
+
- **Zep Evaluator** – Add or query data
|
|
35
35
|
- **Easily extendable** with custom evaluation approaches
|
|
36
36
|
|
|
37
|
-
###
|
|
37
|
+
### New Router System
|
|
38
|
+
- **Pluggable router system** for dynamic agent chaining
|
|
39
|
+
- Built-in support for multiple routing strategies:
|
|
40
|
+
- **Default Router** – Uses the agent's hand_off property
|
|
41
|
+
- **LLM Router** – Uses an LLM to determine the next agent
|
|
42
|
+
- **Agent Router** – Uses a dedicated agent to make routing decisions
|
|
43
|
+
- **Easily extendable** with custom routing approaches
|
|
44
|
+
|
|
45
|
+
### REST API Server
|
|
46
|
+
- **FastAPI-based** HTTP server for exposing agents
|
|
47
|
+
- **Synchronous and asynchronous** execution modes
|
|
48
|
+
- **Run status tracking** with unique run IDs
|
|
49
|
+
- **Agent discovery** endpoint to list available agents
|
|
50
|
+
- **Simple integration** with existing Flock instances
|
|
51
|
+
|
|
52
|
+
### Auto-Handoff Feature
|
|
53
|
+
- **Dynamic agent chaining** without explicit handoff definitions
|
|
54
|
+
- **LLM-powered routing** to determine the best next agent
|
|
55
|
+
- **Emergent behavior** in multi-agent systems
|
|
56
|
+
- **Simple to use** with the "auto_handoff" string value
|
|
57
|
+
|
|
58
|
+
### New high end examples like the Repository Analyzer
|
|
59
|
+
- **Automatic documentation generation** for any codebase
|
|
60
|
+
- **Rule-based version** using custom evaluators
|
|
61
|
+
- **LLM-based version** for more flexible and powerful analysis
|
|
62
|
+
- **Comprehensive documentation** including overview, architecture, components, and more
|
|
63
|
+
|
|
64
|
+
### FlockFactory
|
|
38
65
|
- Provides **pre-configured agents**, so you don't have to manage modules and evaluators manually!
|
|
39
66
|
|
|
40
67
|
### Built-in Modules
|
|
41
68
|
- **Memory Module** – Persistent agent memory
|
|
42
69
|
- **Output Module** – Advanced output formatting and storage
|
|
43
70
|
- **Metrics Module** – Detailed performance tracking
|
|
71
|
+
- **Zep Module** – Uses Zep for Knowledge Graphs
|
|
44
72
|
|
|
45
73
|
---
|
|
46
74
|
|
|
@@ -99,7 +127,7 @@ See? **Basically nothing changed!** Just more modular and flexible.
|
|
|
99
127
|
|
|
100
128
|
---
|
|
101
129
|
|
|
102
|
-
##
|
|
130
|
+
## Installation
|
|
103
131
|
|
|
104
132
|
```bash
|
|
105
133
|
pip install flock-core>=0.3.0
|
|
@@ -107,5 +135,5 @@ pip install flock-core>=0.3.0
|
|
|
107
135
|
|
|
108
136
|
---
|
|
109
137
|
|
|
110
|
-
**Full documentation**: [
|
|
111
|
-
**GitHub**: [github.com/flock
|
|
138
|
+
**Full documentation**: [https://whiteducksoftware.github.io/flock](https://whiteducksoftware.github.io/flock)
|
|
139
|
+
**GitHub**: [https://github.com/whiteducksoftware/flock](https://github.com/whiteducksoftware/flock)
|
flock/core/context/context.py
CHANGED
|
@@ -7,7 +7,7 @@ from opentelemetry import trace
|
|
|
7
7
|
|
|
8
8
|
from flock.core.context.context_vars import FLOCK_LAST_AGENT, FLOCK_LAST_RESULT
|
|
9
9
|
from flock.core.logging.logging import get_logger
|
|
10
|
-
from flock.core.
|
|
10
|
+
from flock.core.serialization.serializable import Serializable
|
|
11
11
|
|
|
12
12
|
logger = get_logger("context")
|
|
13
13
|
tracer = trace.get_tracer(__name__)
|
flock/core/flock_agent.py
CHANGED
|
@@ -5,15 +5,15 @@ import json
|
|
|
5
5
|
import os
|
|
6
6
|
from abc import ABC
|
|
7
7
|
from collections.abc import Callable
|
|
8
|
-
from typing import Any, TypeVar
|
|
8
|
+
from typing import Any, TypeVar
|
|
9
9
|
|
|
10
10
|
import cloudpickle
|
|
11
11
|
from opentelemetry import trace
|
|
12
12
|
from pydantic import BaseModel, Field
|
|
13
13
|
|
|
14
|
-
from flock.core.context.context import FlockContext
|
|
15
14
|
from flock.core.flock_evaluator import FlockEvaluator
|
|
16
15
|
from flock.core.flock_module import FlockModule
|
|
16
|
+
from flock.core.flock_router import FlockRouter
|
|
17
17
|
from flock.core.logging.logging import get_logger
|
|
18
18
|
|
|
19
19
|
logger = get_logger("agent")
|
|
@@ -23,21 +23,6 @@ tracer = trace.get_tracer(__name__)
|
|
|
23
23
|
T = TypeVar("T", bound="FlockAgent")
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
class HandOff(BaseModel):
|
|
27
|
-
"""Base class for handoff returns."""
|
|
28
|
-
|
|
29
|
-
next_agent: Union[str, "FlockAgent"] = Field(
|
|
30
|
-
default="", description="Next agent to invoke"
|
|
31
|
-
)
|
|
32
|
-
input: dict[str, Any] = Field(
|
|
33
|
-
default_factory=dict,
|
|
34
|
-
description="Input data for the next agent",
|
|
35
|
-
)
|
|
36
|
-
context: FlockContext = Field(
|
|
37
|
-
default=None, descrio="Override context parameters"
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
|
|
41
26
|
class FlockAgent(BaseModel, ABC):
|
|
42
27
|
name: str = Field(..., description="Unique identifier for the agent.")
|
|
43
28
|
model: str | None = Field(
|
|
@@ -72,12 +57,9 @@ class FlockAgent(BaseModel, ABC):
|
|
|
72
57
|
description="Set to True to enable caching of the agent's results.",
|
|
73
58
|
)
|
|
74
59
|
|
|
75
|
-
|
|
76
|
-
None,
|
|
77
|
-
description=
|
|
78
|
-
"Specifies the next agent in the workflow or a callable that determines the handoff. "
|
|
79
|
-
"This allows chaining of agents."
|
|
80
|
-
),
|
|
60
|
+
handoff_router: FlockRouter | None = Field(
|
|
61
|
+
default=None,
|
|
62
|
+
description="Router to use for determining the next agent in the workflow.",
|
|
81
63
|
)
|
|
82
64
|
|
|
83
65
|
evaluator: FlockEvaluator = Field(
|
flock/core/flock_factory.py
CHANGED
|
@@ -3,14 +3,17 @@
|
|
|
3
3
|
from collections.abc import Callable
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
|
-
from flock.core.flock_agent import FlockAgent
|
|
6
|
+
from flock.core.flock_agent import FlockAgent
|
|
7
7
|
from flock.core.logging.formatters.themes import OutputTheme
|
|
8
8
|
from flock.evaluators.declarative.declarative_evaluator import (
|
|
9
9
|
DeclarativeEvaluator,
|
|
10
10
|
DeclarativeEvaluatorConfig,
|
|
11
11
|
)
|
|
12
|
-
from flock.modules.performance.metrics_module import MetricsModule, MetricsModuleConfig
|
|
13
12
|
from flock.modules.output.output_module import OutputModule, OutputModuleConfig
|
|
13
|
+
from flock.modules.performance.metrics_module import (
|
|
14
|
+
MetricsModule,
|
|
15
|
+
MetricsModuleConfig,
|
|
16
|
+
)
|
|
14
17
|
|
|
15
18
|
|
|
16
19
|
class FlockFactory:
|
|
@@ -24,7 +27,6 @@ class FlockFactory:
|
|
|
24
27
|
input: str | Callable[..., str] | None = None,
|
|
25
28
|
output: str | Callable[..., str] | None = None,
|
|
26
29
|
tools: list[Callable[..., Any] | Any] | None = None,
|
|
27
|
-
hand_off: str | HandOff | Callable[..., HandOff] | None = None,
|
|
28
30
|
use_cache: bool = True,
|
|
29
31
|
enable_rich_tables: bool = False,
|
|
30
32
|
output_theme: OutputTheme = OutputTheme.abernathy,
|
|
@@ -53,7 +55,6 @@ class FlockFactory:
|
|
|
53
55
|
input=input,
|
|
54
56
|
output=output,
|
|
55
57
|
tools=tools,
|
|
56
|
-
hand_off=hand_off,
|
|
57
58
|
model=model,
|
|
58
59
|
description=description,
|
|
59
60
|
evaluator=evaluator,
|
|
@@ -65,7 +66,9 @@ class FlockFactory:
|
|
|
65
66
|
)
|
|
66
67
|
output_module = OutputModule("output", config=output_config)
|
|
67
68
|
|
|
68
|
-
metrics_config = MetricsModuleConfig(
|
|
69
|
+
metrics_config = MetricsModuleConfig(
|
|
70
|
+
latency_threshold_ms=alert_latency_threshold_ms
|
|
71
|
+
)
|
|
69
72
|
metrics_module = MetricsModule("metrics", config=metrics_config)
|
|
70
73
|
|
|
71
74
|
agent.add_module(output_module)
|
flock/core/flock_module.py
CHANGED
|
@@ -43,7 +43,9 @@ class FlockModule(BaseModel, ABC):
|
|
|
43
43
|
2. Using FlockModuleConfig.with_fields() to create a config class
|
|
44
44
|
"""
|
|
45
45
|
|
|
46
|
-
name: str = Field(
|
|
46
|
+
name: str = Field(
|
|
47
|
+
default="", description="Unique identifier for the module"
|
|
48
|
+
)
|
|
47
49
|
config: FlockModuleConfig = Field(
|
|
48
50
|
default_factory=FlockModuleConfig, description="Module configuration"
|
|
49
51
|
)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Base router class for the Flock framework."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import Any, Literal
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from flock.core.context.context import FlockContext
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class HandOffRequest(BaseModel):
|
|
12
|
+
"""Base class for handoff returns."""
|
|
13
|
+
|
|
14
|
+
next_agent: str = Field(default="", description="Next agent to invoke")
|
|
15
|
+
# match = use the output fields of the current agent that also exists as input field of the next agent
|
|
16
|
+
# add = add the output of the current agent to the input of the next agent
|
|
17
|
+
hand_off_mode: Literal["match", "add"] = Field(default="match")
|
|
18
|
+
override_next_agent: Any | None = Field(
|
|
19
|
+
default=None,
|
|
20
|
+
description="Override the next agent to hand off to",
|
|
21
|
+
)
|
|
22
|
+
override_context: FlockContext | None = Field(
|
|
23
|
+
default=None, descrio="Override context parameters"
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class FlockRouterConfig(BaseModel):
|
|
28
|
+
"""Configuration for a router.
|
|
29
|
+
|
|
30
|
+
This class defines the configuration parameters for a router.
|
|
31
|
+
Subclasses can extend this to add additional parameters.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
enabled: bool = Field(
|
|
35
|
+
default=True, description="Whether the router is enabled"
|
|
36
|
+
)
|
|
37
|
+
agents: list[str] | None = Field(
|
|
38
|
+
default=None,
|
|
39
|
+
description="List of agents to choose from",
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class FlockRouter(BaseModel, ABC):
|
|
44
|
+
"""Base class for all routers.
|
|
45
|
+
|
|
46
|
+
A router is responsible for determining the next agent in a workflow
|
|
47
|
+
based on the current agent's output.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
name: str = Field(..., description="Name of the router")
|
|
51
|
+
config: FlockRouterConfig = Field(default_factory=FlockRouterConfig)
|
|
52
|
+
|
|
53
|
+
@abstractmethod
|
|
54
|
+
async def route(
|
|
55
|
+
self,
|
|
56
|
+
current_agent: Any,
|
|
57
|
+
result: dict[str, Any],
|
|
58
|
+
context: FlockContext,
|
|
59
|
+
) -> HandOffRequest:
|
|
60
|
+
"""Determine the next agent to hand off to based on the current agent's output.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
current_agent: The agent that just completed execution
|
|
64
|
+
result: The output from the current agent
|
|
65
|
+
context: The global execution context
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
A HandOff object containing the next agent and input data
|
|
69
|
+
"""
|
|
70
|
+
pass
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import cloudpickle
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class SecureSerializer:
|
|
5
|
+
"""Security-focused serialization system with capability controls for Flock objects."""
|
|
6
|
+
|
|
7
|
+
# Define capability levels for different modules
|
|
8
|
+
MODULE_CAPABILITIES = {
|
|
9
|
+
# Core Python - unrestricted
|
|
10
|
+
"builtins": "unrestricted",
|
|
11
|
+
"datetime": "unrestricted",
|
|
12
|
+
"re": "unrestricted",
|
|
13
|
+
"math": "unrestricted",
|
|
14
|
+
"json": "unrestricted",
|
|
15
|
+
# Framework modules - unrestricted
|
|
16
|
+
"flock": "unrestricted",
|
|
17
|
+
# System modules - restricted but allowed
|
|
18
|
+
"os": "restricted",
|
|
19
|
+
"io": "restricted",
|
|
20
|
+
"sys": "restricted",
|
|
21
|
+
"subprocess": "high_risk",
|
|
22
|
+
# Network modules - high risk
|
|
23
|
+
"socket": "high_risk",
|
|
24
|
+
"requests": "high_risk",
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
# Functions that should never be serialized
|
|
28
|
+
BLOCKED_FUNCTIONS = {
|
|
29
|
+
"os.system",
|
|
30
|
+
"os.popen",
|
|
31
|
+
"os.spawn",
|
|
32
|
+
"os.exec",
|
|
33
|
+
"subprocess.call",
|
|
34
|
+
"subprocess.run",
|
|
35
|
+
"subprocess.Popen",
|
|
36
|
+
"eval",
|
|
37
|
+
"exec",
|
|
38
|
+
"__import__",
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@staticmethod
|
|
42
|
+
def _get_module_capability(module_name):
|
|
43
|
+
"""Get the capability level for a module."""
|
|
44
|
+
for prefix, level in SecureSerializer.MODULE_CAPABILITIES.items():
|
|
45
|
+
if module_name == prefix or module_name.startswith(f"{prefix}."):
|
|
46
|
+
return level
|
|
47
|
+
return "unknown" # Default to unknown for unlisted modules
|
|
48
|
+
|
|
49
|
+
@staticmethod
|
|
50
|
+
def _is_safe_callable(obj):
|
|
51
|
+
"""Check if a callable is safe to serialize."""
|
|
52
|
+
if not callable(obj) or isinstance(obj, type):
|
|
53
|
+
return True, "Not a callable function"
|
|
54
|
+
|
|
55
|
+
module = obj.__module__
|
|
56
|
+
func_name = (
|
|
57
|
+
f"{module}.{obj.__name__}"
|
|
58
|
+
if hasattr(obj, "__name__")
|
|
59
|
+
else "unknown"
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# Check against blocked functions
|
|
63
|
+
if func_name in SecureSerializer.BLOCKED_FUNCTIONS:
|
|
64
|
+
return False, f"Function {func_name} is explicitly blocked"
|
|
65
|
+
|
|
66
|
+
# Check module capability level
|
|
67
|
+
capability = SecureSerializer._get_module_capability(module)
|
|
68
|
+
if capability == "unknown":
|
|
69
|
+
return False, f"Module {module} has unknown security capability"
|
|
70
|
+
|
|
71
|
+
return True, capability
|
|
72
|
+
|
|
73
|
+
@staticmethod
|
|
74
|
+
def serialize(obj, allow_restricted=True, allow_high_risk=False):
|
|
75
|
+
"""Serialize an object with capability checks."""
|
|
76
|
+
if callable(obj) and not isinstance(obj, type):
|
|
77
|
+
is_safe, capability = SecureSerializer._is_safe_callable(obj)
|
|
78
|
+
|
|
79
|
+
if not is_safe:
|
|
80
|
+
raise ValueError(
|
|
81
|
+
f"Cannot serialize unsafe callable: {capability}"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
if capability == "high_risk" and not allow_high_risk:
|
|
85
|
+
raise ValueError(
|
|
86
|
+
f"High risk callable {obj.__module__}.{obj.__name__} requires explicit permission"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
if capability == "restricted" and not allow_restricted:
|
|
90
|
+
raise ValueError(
|
|
91
|
+
f"Restricted callable {obj.__module__}.{obj.__name__} requires explicit permission"
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# Store metadata about the callable for verification during deserialization
|
|
95
|
+
metadata = {
|
|
96
|
+
"module": obj.__module__,
|
|
97
|
+
"name": getattr(obj, "__name__", "unknown"),
|
|
98
|
+
"capability": capability,
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
"__serialized_callable__": True,
|
|
103
|
+
"data": cloudpickle.dumps(obj).hex(),
|
|
104
|
+
"metadata": metadata,
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if isinstance(obj, list):
|
|
108
|
+
return [
|
|
109
|
+
SecureSerializer.serialize(
|
|
110
|
+
item, allow_restricted, allow_high_risk
|
|
111
|
+
)
|
|
112
|
+
for item in obj
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
if isinstance(obj, dict):
|
|
116
|
+
return {
|
|
117
|
+
k: SecureSerializer.serialize(
|
|
118
|
+
v, allow_restricted, allow_high_risk
|
|
119
|
+
)
|
|
120
|
+
for k, v in obj.items()
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return obj
|
|
124
|
+
|
|
125
|
+
@staticmethod
|
|
126
|
+
def deserialize(obj, allow_restricted=True, allow_high_risk=False):
|
|
127
|
+
"""Deserialize an object with capability enforcement."""
|
|
128
|
+
if isinstance(obj, dict) and obj.get("__serialized_callable__") is True:
|
|
129
|
+
# Validate the capability level during deserialization
|
|
130
|
+
metadata = obj.get("metadata", {})
|
|
131
|
+
capability = metadata.get("capability", "unknown")
|
|
132
|
+
|
|
133
|
+
if capability == "high_risk" and not allow_high_risk:
|
|
134
|
+
raise ValueError(
|
|
135
|
+
f"Cannot deserialize high risk callable {metadata.get('module')}.{metadata.get('name')}"
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
if capability == "restricted" and not allow_restricted:
|
|
139
|
+
raise ValueError(
|
|
140
|
+
f"Cannot deserialize restricted callable {metadata.get('module')}.{metadata.get('name')}"
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
try:
|
|
144
|
+
callable_obj = cloudpickle.loads(bytes.fromhex(obj["data"]))
|
|
145
|
+
|
|
146
|
+
# Additional verification that the deserialized object matches its metadata
|
|
147
|
+
if callable_obj.__module__ != metadata.get("module") or (
|
|
148
|
+
hasattr(callable_obj, "__name__")
|
|
149
|
+
and callable_obj.__name__ != metadata.get("name")
|
|
150
|
+
):
|
|
151
|
+
raise ValueError(
|
|
152
|
+
"Callable metadata mismatch - possible tampering detected"
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
return callable_obj
|
|
156
|
+
except Exception as e:
|
|
157
|
+
raise ValueError(f"Failed to deserialize callable: {e!s}")
|
|
158
|
+
|
|
159
|
+
if isinstance(obj, list):
|
|
160
|
+
return [
|
|
161
|
+
SecureSerializer.deserialize(
|
|
162
|
+
item, allow_restricted, allow_high_risk
|
|
163
|
+
)
|
|
164
|
+
for item in obj
|
|
165
|
+
]
|
|
166
|
+
|
|
167
|
+
if isinstance(obj, dict) and "__serialized_callable__" not in obj:
|
|
168
|
+
return {
|
|
169
|
+
k: SecureSerializer.deserialize(
|
|
170
|
+
v, allow_restricted, allow_high_risk
|
|
171
|
+
)
|
|
172
|
+
for k, v in obj.items()
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return obj
|
|
@@ -40,6 +40,8 @@ class ZepEvaluator(FlockEvaluator, DSPyIntegrationMixin, PromptParserMixin):
|
|
|
40
40
|
zep_api_key=self.config.zep_api_key,
|
|
41
41
|
zep_url=self.config.zep_url,
|
|
42
42
|
min_fact_rating=self.config.min_fact_rating,
|
|
43
|
+
enable_read=True,
|
|
44
|
+
enable_write=True,
|
|
43
45
|
),
|
|
44
46
|
)
|
|
45
47
|
client = zep.get_client()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Routers for the Flock framework."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Agent-based router implementation for the Flock framework."""
|