flock-core 0.3.6__py3-none-any.whl → 0.3.10__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_manager.py +3 -0
- flock/core/context/context_vars.py +1 -0
- flock/core/flock.py +2 -1
- flock/core/flock_agent.py +10 -23
- flock/core/flock_factory.py +9 -6
- flock/core/flock_module.py +3 -1
- flock/core/flock_router.py +70 -0
- flock/core/util/cli_helper.py +1 -3
- flock/evaluators/zep/zep_evaluator.py +2 -0
- flock/modules/performance/metrics_module.py +185 -189
- 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 +77 -34
- {flock_core-0.3.6.dist-info → flock_core-0.3.10.dist-info}/METADATA +6 -6
- {flock_core-0.3.6.dist-info → flock_core-0.3.10.dist-info}/RECORD +25 -16
- {flock_core-0.3.6.dist-info → flock_core-0.3.10.dist-info}/WHEEL +0 -0
- {flock_core-0.3.6.dist-info → flock_core-0.3.10.dist-info}/entry_points.txt +0 -0
- {flock_core-0.3.6.dist-info → flock_core-0.3.10.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)
|
|
@@ -5,6 +5,7 @@ from flock.core.context.context_vars import (
|
|
|
5
5
|
FLOCK_CURRENT_AGENT,
|
|
6
6
|
FLOCK_INITIAL_INPUT,
|
|
7
7
|
FLOCK_LOCAL_DEBUG,
|
|
8
|
+
FLOCK_MODEL,
|
|
8
9
|
FLOCK_RUN_ID,
|
|
9
10
|
)
|
|
10
11
|
|
|
@@ -15,6 +16,7 @@ def initialize_context(
|
|
|
15
16
|
input_data: dict,
|
|
16
17
|
run_id: str,
|
|
17
18
|
local_debug: bool,
|
|
19
|
+
model: str,
|
|
18
20
|
) -> None:
|
|
19
21
|
"""Initialize the FlockContext with standard variables before running an agent.
|
|
20
22
|
|
|
@@ -32,3 +34,4 @@ def initialize_context(
|
|
|
32
34
|
context.set_variable(FLOCK_LOCAL_DEBUG, local_debug)
|
|
33
35
|
context.run_id = run_id
|
|
34
36
|
context.set_variable(FLOCK_RUN_ID, run_id)
|
|
37
|
+
context.set_variable(FLOCK_MODEL, model)
|
flock/core/flock.py
CHANGED
|
@@ -135,7 +135,7 @@ class Flock:
|
|
|
135
135
|
with tracer.start_as_current_span("add_agent") as span:
|
|
136
136
|
span.set_attribute("agent_name", agent.name)
|
|
137
137
|
if not agent.model:
|
|
138
|
-
agent.
|
|
138
|
+
agent.set_model(self.model)
|
|
139
139
|
logger.debug(
|
|
140
140
|
f"Using default model for agent {agent.name}",
|
|
141
141
|
model=self.model,
|
|
@@ -443,6 +443,7 @@ class Flock:
|
|
|
443
443
|
self.input,
|
|
444
444
|
run_id,
|
|
445
445
|
not self.enable_temporal,
|
|
446
|
+
self.model,
|
|
446
447
|
)
|
|
447
448
|
|
|
448
449
|
logger.info(
|
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(
|
|
@@ -218,6 +200,11 @@ class FlockAgent(BaseModel, ABC):
|
|
|
218
200
|
"""Run the agent with the given inputs and return its generated output."""
|
|
219
201
|
return asyncio.run(self.run_async(inputs))
|
|
220
202
|
|
|
203
|
+
def set_model(self, model: str):
|
|
204
|
+
"""Set the model for the agent."""
|
|
205
|
+
self.model = model
|
|
206
|
+
self.evaluator.config.model = model
|
|
207
|
+
|
|
221
208
|
async def run_async(self, inputs: dict[str, Any]) -> dict[str, Any]:
|
|
222
209
|
with tracer.start_as_current_span("agent.run") as span:
|
|
223
210
|
span.set_attribute("agent.name", self.name)
|
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:
|
|
@@ -20,11 +23,10 @@ class FlockFactory:
|
|
|
20
23
|
def create_default_agent(
|
|
21
24
|
name: str,
|
|
22
25
|
description: str | Callable[..., str] | None = None,
|
|
23
|
-
model: str | Callable[..., str] | None =
|
|
26
|
+
model: str | Callable[..., str] | None = None,
|
|
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
|
flock/core/util/cli_helper.py
CHANGED
|
@@ -52,7 +52,7 @@ def init_console(clear_screen: bool = True):
|
|
|
52
52
|
│ ▒█▀▀▀ █░░ █▀▀█ █▀▀ █░█ │
|
|
53
53
|
│ ▒█▀▀▀ █░░ █░░█ █░░ █▀▄ │
|
|
54
54
|
│ ▒█░░░ ▀▀▀ ▀▀▀▀ ▀▀▀ ▀░▀ │
|
|
55
|
-
╰━━━━━━━━━v{__version__}
|
|
55
|
+
╰━━━━━━━━━v{__version__}━━━━━━━━╯
|
|
56
56
|
🦆 🐤 🐧 🐓
|
|
57
57
|
""",
|
|
58
58
|
justify="center",
|
|
@@ -83,5 +83,3 @@ def display_banner_no_version():
|
|
|
83
83
|
)
|
|
84
84
|
console.print(banner_text)
|
|
85
85
|
console.print(f"[bold]white duck GmbH[/] - [cyan]https://whiteduck.de[/]\n")
|
|
86
|
-
|
|
87
|
-
|
|
@@ -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()
|