flock-core 0.2.17__py3-none-any.whl → 0.3.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of flock-core might be problematic. Click here for more details.

Files changed (32) hide show
  1. flock/__init__.py +39 -29
  2. flock/cli/assets/release_notes.md +111 -0
  3. flock/cli/constants.py +1 -0
  4. flock/cli/load_release_notes.py +23 -0
  5. flock/core/__init__.py +12 -1
  6. flock/core/context/context.py +10 -5
  7. flock/core/flock.py +61 -21
  8. flock/core/flock_agent.py +112 -442
  9. flock/core/flock_evaluator.py +49 -0
  10. flock/core/flock_factory.py +73 -0
  11. flock/core/flock_module.py +77 -0
  12. flock/{interpreter → core/interpreter}/python_interpreter.py +9 -1
  13. flock/core/logging/formatters/themes.py +1 -1
  14. flock/core/logging/logging.py +119 -15
  15. flock/core/mixin/dspy_integration.py +11 -8
  16. flock/core/registry/agent_registry.py +4 -2
  17. flock/core/tools/basic_tools.py +1 -1
  18. flock/core/util/cli_helper.py +59 -2
  19. flock/evaluators/declarative/declarative_evaluator.py +52 -0
  20. flock/evaluators/natural_language/natural_language_evaluator.py +66 -0
  21. flock/modules/callback/callback_module.py +86 -0
  22. flock/modules/memory/memory_module.py +235 -0
  23. flock/modules/memory/memory_parser.py +125 -0
  24. flock/modules/memory/memory_storage.py +736 -0
  25. flock/modules/output/output_module.py +194 -0
  26. flock/modules/performance/metrics_module.py +477 -0
  27. flock/themes/aardvark-blue.toml +1 -1
  28. {flock_core-0.2.17.dist-info → flock_core-0.3.1.dist-info}/METADATA +112 -4
  29. {flock_core-0.2.17.dist-info → flock_core-0.3.1.dist-info}/RECORD +32 -19
  30. {flock_core-0.2.17.dist-info → flock_core-0.3.1.dist-info}/WHEEL +0 -0
  31. {flock_core-0.2.17.dist-info → flock_core-0.3.1.dist-info}/entry_points.txt +0 -0
  32. {flock_core-0.2.17.dist-info → flock_core-0.3.1.dist-info}/licenses/LICENSE +0 -0
flock/__init__.py CHANGED
@@ -1,6 +1,7 @@
1
1
  """Flock package initialization."""
2
2
 
3
- from flock.cli.constants import CLI_THEME_BUILDER
3
+ from flock.cli.constants import CLI_EXIT, CLI_NOTES, CLI_THEME_BUILDER
4
+ from flock.cli.load_release_notes import load_release_notes
4
5
  from flock.core.logging.formatters.theme_builder import theme_builder
5
6
 
6
7
 
@@ -20,37 +21,46 @@ def main():
20
21
  CLI_START_WEB_SERVER,
21
22
  )
22
23
  from flock.cli.load_flock import load_flock
23
- from flock.core.util.cli_helper import display_banner
24
+ from flock.core.util.cli_helper import init_console
24
25
 
25
26
  console = Console()
27
+ while True:
28
+ init_console()
26
29
 
27
- display_banner()
28
-
29
- console.print("Flock Management Console\n", style="bold green")
30
-
31
- result = questionary.select(
32
- "What do you want to do?",
33
- choices=[
34
- questionary.Separator(line=" "),
35
- # CLI_CREATE_AGENT,
36
- # CLI_CREATE_FLOCK,
37
- # CLI_LOAD_AGENT,
38
- CLI_LOAD_FLOCK,
39
- # CLI_LOAD_EXAMPLE,
40
- questionary.Separator(),
41
- CLI_THEME_BUILDER,
42
- CLI_SETTINGS,
43
- questionary.Separator(),
44
- CLI_START_ADVANCED_MODE,
45
- CLI_START_WEB_SERVER,
46
- "Exit",
47
- ],
48
- ).ask()
49
-
50
- if result == CLI_LOAD_FLOCK:
51
- load_flock()
52
- if result == CLI_THEME_BUILDER:
53
- theme_builder()
30
+ console.print("Flock Management Console\n", style="bold green")
31
+
32
+ result = questionary.select(
33
+ "What do you want to do?",
34
+ choices=[
35
+ questionary.Separator(line=" "),
36
+ # CLI_CREATE_AGENT,
37
+ # CLI_CREATE_FLOCK,
38
+ # CLI_LOAD_AGENT,
39
+ CLI_LOAD_FLOCK,
40
+ # CLI_LOAD_EXAMPLE,
41
+ questionary.Separator(),
42
+ CLI_THEME_BUILDER,
43
+ CLI_SETTINGS,
44
+ questionary.Separator(),
45
+ CLI_START_ADVANCED_MODE,
46
+ CLI_START_WEB_SERVER,
47
+ questionary.Separator(),
48
+ CLI_NOTES,
49
+ CLI_EXIT,
50
+ ],
51
+ ).ask()
52
+
53
+ if result == CLI_LOAD_FLOCK:
54
+ load_flock()
55
+ if result == CLI_THEME_BUILDER:
56
+ theme_builder()
57
+ if result == CLI_NOTES:
58
+ load_release_notes()
59
+ if result == CLI_EXIT:
60
+ break
61
+ input("\nPress Enter to continue...\n\n")
62
+
63
+ console.clear()
54
64
 
55
65
 
56
66
  if __name__ == "__main__":
@@ -0,0 +1,111 @@
1
+
2
+ # Flock v0.3 - Hummingbird
3
+
4
+ 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.
5
+
6
+ Modules and evaluators were the last missing pieces to fully modularize Flock.
7
+
8
+ Worried this might lead to hard-to-manage boilerplate? No problem! **FlockFactory** provides pre-configured agents, making interaction with modules and evaluators **purely optional**, so you can focus on **what** the agent does, not **how** it works.
9
+
10
+ But if you want **total control** over your agent, feel free to dive into these new additions. They unlock **crazy new possibilities** in Flock!
11
+
12
+ Like a hummingbird, modules are small and nimble code packages. Put enough of them inside a flock, and... well, even we don't know what happens next.
13
+
14
+ ### Other notable additions:
15
+ - **CLI Interface** – Flock now has a command-line interface
16
+ - **Color-coded logging** – Better debugging experience
17
+ - **New examples**
18
+ - ...and much more!
19
+
20
+ ---
21
+
22
+ ## Core Changes
23
+
24
+ ### New Module System
25
+ - **Complete redesign** of the module architecture
26
+ - Simple yet powerful lifecycle hooks: `initialize`, `pre_evaluate`, `post_evaluate`, `terminate`
27
+ - **Easy-to-implement** module interface
28
+ - **Configuration system** for clean parameter management
29
+
30
+ ### New Evaluator System
31
+ - **Pluggable evaluation system**
32
+ - Built-in support for multiple evaluation strategies:
33
+ - **Declarative Evaluator** – The default way Flock is designed
34
+ - **Natural Language Evaluator** – Use "classic" prompting
35
+ - **Easily extendable** with custom evaluation approaches
36
+
37
+ ### FlockFactory
38
+ - Provides **pre-configured agents**, so you don't have to manage modules and evaluators manually!
39
+
40
+ ### Built-in Modules
41
+ - **Memory Module** – Persistent agent memory
42
+ - **Output Module** – Advanced output formatting and storage
43
+ - **Metrics Module** – Detailed performance tracking
44
+
45
+ ---
46
+
47
+ ## Breaking Changes
48
+ - **Removed callback handlers** from `FlockAgent` in favor of modules
49
+ - **Changed agent initialization** pattern to support evaluators
50
+ - **Simplified module lifecycle hooks** (removed redundant pre/post hooks)
51
+
52
+ ---
53
+
54
+ ## Small Changes & Fixes
55
+
56
+ ### Theme Designer
57
+
58
+ ### Color Coded Logging
59
+
60
+ ---
61
+
62
+ ## Code Rundown
63
+
64
+ ### Old way:
65
+ ```python
66
+ agent = FlockAgent(
67
+ name="bloggy",
68
+ input="blog_idea",
69
+ output="funny_blog_title, blog_headers",
70
+ )
71
+ flock.add_agent(bloggy)
72
+ ```
73
+
74
+ ### New way:
75
+ ```python
76
+ bloggy = FlockFactory.create_default_agent(
77
+ name="bloggy",
78
+ input="blog_idea",
79
+ output="funny_blog_title, blog_headers",
80
+ )
81
+ flock.add_agent(bloggy)
82
+ ```
83
+
84
+ See? **Basically nothing changed!** Just more modular and flexible.
85
+
86
+ ---
87
+
88
+ ## What's Next?
89
+
90
+ ### Coming in v0.3 updates:
91
+ - **More modules** (built-in RAG coming soon!)
92
+ - **More evaluators**
93
+ - **CLI management tool improvements**
94
+ - **Finishing documentation**
95
+
96
+ ### Looking ahead to v0.4 – *Magpie*:
97
+ - **Flock WebUI** – Real-time monitoring, no-code agent creation & management
98
+ - **Seamless deployment** – Kubernetes, Docker, and enterprise-ready solutions
99
+
100
+ ---
101
+
102
+ ## 🛠 Installation
103
+
104
+ ```bash
105
+ pip install flock-core>=0.3.0
106
+ ```
107
+
108
+ ---
109
+
110
+ **Full documentation**: [docs.flock.ai](https://docs.flock.ai)
111
+ **GitHub**: [github.com/flock-ai](https://github.com/flock-ai)
flock/cli/constants.py CHANGED
@@ -7,6 +7,7 @@ CLI_LOAD_FLOCK = "Load a *.flock file"
7
7
  CLI_THEME_BUILDER = "Theme builder"
8
8
  CLI_LOAD_EXAMPLE = "Load a example"
9
9
  CLI_SETTINGS = "Settings"
10
+ CLI_NOTES = "'Hummingbird' release notes"
10
11
  CLI_START_ADVANCED_MODE = "Start advanced mode (coming soon)"
11
12
  CLI_START_WEB_SERVER = "Start web server (coming soon)"
12
13
  CLI_EXIT = "Exit"
@@ -0,0 +1,23 @@
1
+ from pathlib import Path
2
+
3
+ from flock.core.util.cli_helper import display_hummingbird
4
+
5
+
6
+ def load_release_notes():
7
+ """Load release notes."""
8
+ from rich.console import Console
9
+ from rich.markdown import Markdown
10
+
11
+ from flock.core.util.cli_helper import init_console
12
+
13
+ console = Console()
14
+ file_path = Path(__file__).parent / "assets" / "release_notes.md"
15
+
16
+ init_console()
17
+ console.print(Markdown("# *'Hummingbird'* Release Notes"))
18
+ display_hummingbird()
19
+ with open(file_path) as file:
20
+ release_notes = file.read()
21
+
22
+
23
+ console.print(Markdown(release_notes))
flock/core/__init__.py CHANGED
@@ -2,5 +2,16 @@
2
2
 
3
3
  from flock.core.flock import Flock
4
4
  from flock.core.flock_agent import FlockAgent
5
+ from flock.core.flock_evaluator import FlockEvaluator, FlockEvaluatorConfig
6
+ from flock.core.flock_factory import FlockFactory
7
+ from flock.core.flock_module import FlockModule, FlockModuleConfig
5
8
 
6
- __all__ = ["Flock", "FlockAgent"]
9
+ __all__ = [
10
+ "Flock",
11
+ "FlockAgent",
12
+ "FlockEvaluator",
13
+ "FlockEvaluatorConfig",
14
+ "FlockFactory",
15
+ "FlockModule",
16
+ "FlockModuleConfig",
17
+ ]
@@ -1,3 +1,4 @@
1
+ import uuid
1
2
  from dataclasses import asdict, dataclass, field
2
3
  from datetime import datetime
3
4
  from typing import Any, Literal
@@ -14,6 +15,7 @@ tracer = trace.get_tracer(__name__)
14
15
 
15
16
  @dataclass
16
17
  class AgentRunRecord:
18
+ id: str = field(default="")
17
19
  agent: str = field(default="")
18
20
  data: dict[str, Any] = field(default_factory=dict)
19
21
  timestamp: str = field(default="")
@@ -49,6 +51,7 @@ class FlockContext(Serializable):
49
51
  called_from: str,
50
52
  ) -> None:
51
53
  record = AgentRunRecord(
54
+ id=agent_name + "_" + uuid.uuid4().hex[:4],
52
55
  agent=agent_name,
53
56
  data=data.copy(),
54
57
  timestamp=timestamp,
@@ -61,7 +64,7 @@ class FlockContext(Serializable):
61
64
  self.set_variable(FLOCK_LAST_RESULT, data)
62
65
  self.set_variable(FLOCK_LAST_AGENT, agent_name)
63
66
  logger.info(
64
- "Agent run recorded",
67
+ f"Agent run recorded - run_id '{record.id}'",
65
68
  agent=agent_name,
66
69
  timestamp=timestamp,
67
70
  data=data,
@@ -80,12 +83,14 @@ class FlockContext(Serializable):
80
83
  old_value = self.state.get(key)
81
84
  self.state[key] = value
82
85
  if old_value != value:
86
+ escaped_value = str(value).replace("{", "{{").replace("}", "}}")
87
+
83
88
  logger.info(
84
- "Context variable updated",
85
- variable=key,
86
- old=old_value,
87
- new=value,
89
+ "Context variable updated - {} -> {}",
90
+ key,
91
+ escaped_value, # Arguments in order
88
92
  )
93
+
89
94
  current_span = trace.get_current_span()
90
95
  if current_span.get_span_context().is_valid:
91
96
  current_span.add_event(
flock/core/flock.py CHANGED
@@ -16,9 +16,9 @@ from flock.core.context.context_manager import initialize_context
16
16
  from flock.core.execution.local_executor import run_local_workflow
17
17
  from flock.core.execution.temporal_executor import run_temporal_workflow
18
18
  from flock.core.flock_agent import FlockAgent
19
- from flock.core.logging.logging import get_logger
19
+ from flock.core.logging.logging import LOGGERS, get_logger, get_module_loggers
20
20
  from flock.core.registry.agent_registry import Registry
21
- from flock.core.util.cli_helper import display_banner
21
+ from flock.core.util.cli_helper import init_console
22
22
  from flock.core.util.input_resolver import top_level_to_keys
23
23
 
24
24
  T = TypeVar("T", bound=FlockAgent)
@@ -27,6 +27,43 @@ TELEMETRY.setup_tracing()
27
27
  tracer = trace.get_tracer(__name__)
28
28
 
29
29
 
30
+ def init_loggers(enable_logging: bool | list[str] = False):
31
+ """Initialize the loggers for the Flock system.
32
+
33
+ Args:
34
+ enable_logging (bool): If True, enable verbose logging. Defaults to False.
35
+ """
36
+ if isinstance(enable_logging, list):
37
+ for logger in LOGGERS:
38
+ if logger in enable_logging:
39
+ other_loggers = get_logger(logger)
40
+ other_loggers.enable_logging = True
41
+ else:
42
+ other_loggers = get_logger(logger)
43
+ other_loggers.enable_logging = False
44
+ else:
45
+ logger = get_logger("flock")
46
+ logger.enable_logging = enable_logging
47
+ other_loggers = get_logger("interpreter")
48
+ other_loggers.enable_logging = enable_logging
49
+ other_loggers = get_logger("memory")
50
+ other_loggers.enable_logging = enable_logging
51
+ other_loggers = get_logger("activities")
52
+ other_loggers.enable_logging = enable_logging
53
+ other_loggers = get_logger("context")
54
+ other_loggers.enable_logging = enable_logging
55
+ other_loggers = get_logger("registry")
56
+ other_loggers.enable_logging = enable_logging
57
+ other_loggers = get_logger("tools")
58
+ other_loggers.enable_logging = enable_logging
59
+ other_loggers = get_logger("agent")
60
+ other_loggers.enable_logging = enable_logging
61
+
62
+ module_loggers = get_module_loggers()
63
+ for module_logger in module_loggers:
64
+ module_logger.enable_logging = enable_logging
65
+
66
+
30
67
  class Flock:
31
68
  """High-level orchestrator for creating and executing agents.
32
69
 
@@ -37,9 +74,8 @@ class Flock:
37
74
  def __init__(
38
75
  self,
39
76
  model: str = "openai/gpt-4o",
40
- local_debug: bool = False,
41
- enable_logging: bool = False,
42
- show_cli_banner: bool = True,
77
+ enable_temporal: bool = False,
78
+ enable_logging: bool | list[str] = False,
43
79
  ):
44
80
  """Initialize the Flock orchestrator.
45
81
 
@@ -51,32 +87,32 @@ class Flock:
51
87
  """
52
88
  with tracer.start_as_current_span("flock_init") as span:
53
89
  span.set_attribute("model", model)
54
- span.set_attribute("local_debug", local_debug)
90
+ span.set_attribute("enable_temporal", enable_temporal)
55
91
  span.set_attribute("enable_logging", enable_logging)
92
+
93
+ init_loggers(enable_logging)
56
94
  logger.info(
57
95
  "Initializing Flock",
58
96
  model=model,
59
- local_debug=local_debug,
97
+ enable_temporal=enable_temporal,
60
98
  enable_logging=enable_logging,
61
99
  )
62
- logger.enable_logging = enable_logging
63
100
  session_id = get_baggage("session_id")
64
101
  if not session_id:
65
102
  session_id = str(uuid.uuid4())
66
103
  set_baggage("session_id", session_id)
67
104
 
68
- if show_cli_banner:
69
- display_banner()
105
+ init_console()
70
106
 
71
107
  self.agents: dict[str, FlockAgent] = {}
72
108
  self.registry = Registry()
73
109
  self.context = FlockContext()
74
110
  self.model = model
75
- self.local_debug = local_debug
111
+ self.enable_temporal = enable_temporal
76
112
  self.start_agent: FlockAgent | str | None = None
77
113
  self.input: dict = {}
78
114
 
79
- if local_debug:
115
+ if not enable_temporal:
80
116
  os.environ["LOCAL_DEBUG"] = "1"
81
117
  logger.debug("Set LOCAL_DEBUG environment variable")
82
118
  elif "LOCAL_DEBUG" in os.environ:
@@ -110,7 +146,7 @@ class Flock:
110
146
  f"Agent {agent.name} already exists, returning existing instance"
111
147
  )
112
148
  return self.agents[agent.name]
113
- logger.info("Adding new agent")
149
+ logger.info(f"Adding new agent '{agent.name}'")
114
150
 
115
151
  self.agents[agent.name] = agent
116
152
  self.registry.register_agent(agent)
@@ -121,8 +157,11 @@ class Flock:
121
157
  if hasattr(agent, "tools") and agent.tools:
122
158
  for tool in agent.tools:
123
159
  self.registry.register_tool(tool.__name__, tool)
124
- logger.debug("Registered tool", tool_name=tool.__name__)
125
- logger.success("Agent added successfully")
160
+ logger.debug(
161
+ f"Registered tool '{tool.__name__}'",
162
+ tool_name=tool.__name__,
163
+ )
164
+ logger.success(f"'{agent.name}' added successfully")
126
165
  return agent
127
166
 
128
167
  def add_tool(self, tool_name: str, tool: callable):
@@ -362,7 +401,8 @@ class Flock:
362
401
  try:
363
402
  if isinstance(self.start_agent, str):
364
403
  logger.debug(
365
- "Looking up agent by name", agent_name=self.start_agent
404
+ f"Looking up agent '{self.start_agent.name}' in registry",
405
+ agent_name=self.start_agent,
366
406
  )
367
407
  self.start_agent = self.registry.get_agent(self.start_agent)
368
408
  if not self.start_agent:
@@ -377,8 +417,8 @@ class Flock:
377
417
  logger.debug("Using provided context")
378
418
  self.context = context
379
419
  if not run_id:
380
- run_id = f"{self.start_agent.name}_{uuid.uuid4().hex[:4]}"
381
- logger.debug("Generated run ID", run_id=run_id)
420
+ run_id = f"flock_{uuid.uuid4().hex[:4]}"
421
+ logger.debug(f"Generated run ID '{run_id}'", run_id=run_id)
382
422
 
383
423
  set_baggage("run_id", run_id)
384
424
 
@@ -400,16 +440,16 @@ class Flock:
400
440
  self.start_agent.name,
401
441
  self.input,
402
442
  run_id,
403
- self.local_debug,
443
+ not self.enable_temporal,
404
444
  )
405
445
 
406
446
  logger.info(
407
447
  "Starting agent execution",
408
448
  agent=self.start_agent.name,
409
- local_debug=self.local_debug,
449
+ enable_temporal=self.enable_temporal,
410
450
  )
411
451
 
412
- if self.local_debug:
452
+ if not self.enable_temporal:
413
453
  return await run_local_workflow(self.context, box_result)
414
454
  else:
415
455
  return await run_temporal_workflow(self.context, box_result)