flock-core 0.2.13__py3-none-any.whl → 0.2.15__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/__init__.py +56 -0
- flock/cli/constants.py +23 -0
- flock/cli/create_agent.py +1 -0
- flock/cli/create_flock.py +1 -0
- flock/cli/load_agent.py +1 -0
- flock/cli/load_examples.py +1 -0
- flock/cli/load_flock.py +38 -0
- flock/cli/settings.py +1 -0
- flock/config.py +0 -1
- flock/core/execution/local_executor.py +7 -3
- flock/core/execution/temporal_executor.py +1 -8
- flock/core/flock.py +197 -34
- flock/core/flock_agent.py +89 -9
- flock/core/logging/formatters/enum_builder.py +38 -0
- flock/core/logging/formatters/theme_builder.py +2 -6
- flock/core/logging/formatters/themed_formatter.py +127 -19
- flock/core/logging/formatters/themes.py +340 -0
- flock/core/logging/telemetry.py +1 -1
- flock/core/mixin/dspy_integration.py +6 -1
- flock/workflow/activities.py +2 -19
- {flock_core-0.2.13.dist-info → flock_core-0.2.15.dist-info}/METADATA +2 -1
- {flock_core-0.2.13.dist-info → flock_core-0.2.15.dist-info}/RECORD +25 -20
- flock/core/logging/formatters/base_formatter.py +0 -36
- flock/core/logging/formatters/formatter_factory.py +0 -38
- flock/core/logging/formatters/pprint_formatter.py +0 -25
- flock/core/logging/formatters/rich_formatters.py +0 -132
- {flock_core-0.2.13.dist-info → flock_core-0.2.15.dist-info}/WHEEL +0 -0
- {flock_core-0.2.13.dist-info → flock_core-0.2.15.dist-info}/entry_points.txt +0 -0
- {flock_core-0.2.13.dist-info → flock_core-0.2.15.dist-info}/licenses/LICENSE +0 -0
flock/__init__.py
CHANGED
|
@@ -1 +1,57 @@
|
|
|
1
1
|
"""Flock package initialization."""
|
|
2
|
+
|
|
3
|
+
from flock.cli.constants import CLI_THEME_BUILDER
|
|
4
|
+
from flock.core.logging.formatters.theme_builder import theme_builder
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def main():
|
|
8
|
+
"""Main function."""
|
|
9
|
+
import questionary
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
|
|
12
|
+
from flock.cli.constants import (
|
|
13
|
+
CLI_CREATE_AGENT,
|
|
14
|
+
CLI_CREATE_FLOCK,
|
|
15
|
+
CLI_LOAD_AGENT,
|
|
16
|
+
CLI_LOAD_EXAMPLE,
|
|
17
|
+
CLI_LOAD_FLOCK,
|
|
18
|
+
CLI_SETTINGS,
|
|
19
|
+
CLI_START_ADVANCED_MODE,
|
|
20
|
+
CLI_START_WEB_SERVER,
|
|
21
|
+
)
|
|
22
|
+
from flock.cli.load_flock import load_flock
|
|
23
|
+
from flock.core.util.cli_helper import display_banner
|
|
24
|
+
|
|
25
|
+
console = Console()
|
|
26
|
+
|
|
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()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
if __name__ == "__main__":
|
|
57
|
+
main()
|
flock/cli/constants.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Constants for the CLI module."""
|
|
2
|
+
|
|
3
|
+
CLI_CREATE_AGENT = "Create an agent"
|
|
4
|
+
CLI_CREATE_FLOCK = "Create a flock"
|
|
5
|
+
CLI_LOAD_AGENT = "Load an agent"
|
|
6
|
+
CLI_LOAD_FLOCK = "Load a *.flock file"
|
|
7
|
+
CLI_THEME_BUILDER = "Theme builder"
|
|
8
|
+
CLI_LOAD_EXAMPLE = "Load a example"
|
|
9
|
+
CLI_SETTINGS = "Settings"
|
|
10
|
+
CLI_START_ADVANCED_MODE = "Start advanced mode (coming soon)"
|
|
11
|
+
CLI_START_WEB_SERVER = "Start web server (coming soon)"
|
|
12
|
+
CLI_EXIT = "Exit"
|
|
13
|
+
CLI_CHOICES = [
|
|
14
|
+
CLI_CREATE_AGENT,
|
|
15
|
+
CLI_CREATE_FLOCK,
|
|
16
|
+
CLI_LOAD_AGENT,
|
|
17
|
+
CLI_LOAD_FLOCK,
|
|
18
|
+
CLI_LOAD_EXAMPLE,
|
|
19
|
+
CLI_SETTINGS,
|
|
20
|
+
CLI_START_ADVANCED_MODE,
|
|
21
|
+
CLI_START_WEB_SERVER,
|
|
22
|
+
CLI_EXIT,
|
|
23
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# TODO
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# TODO
|
flock/cli/load_agent.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# TODO
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# TODO
|
flock/cli/load_flock.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Load a Flock from a file."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import questionary
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
from rich.markdown import Markdown
|
|
8
|
+
|
|
9
|
+
from flock.core.flock import Flock
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def filter(file_path) -> bool:
|
|
13
|
+
"""Filter function for file selection."""
|
|
14
|
+
path = Path(file_path)
|
|
15
|
+
if path.is_dir():
|
|
16
|
+
return True
|
|
17
|
+
return path.is_file() and path.suffix == ".flock"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def load_flock():
|
|
21
|
+
"""Load a Flock from a file."""
|
|
22
|
+
console = Console()
|
|
23
|
+
|
|
24
|
+
console.print("\nPlease select a *.flock file\n", style="bold green")
|
|
25
|
+
|
|
26
|
+
result = questionary.path("", file_filter=filter).ask()
|
|
27
|
+
|
|
28
|
+
selected_file = Path(result)
|
|
29
|
+
if selected_file.is_file():
|
|
30
|
+
console.print(f"Selected file: {selected_file}", style="bold green")
|
|
31
|
+
|
|
32
|
+
flock = Flock.load_from_file(result)
|
|
33
|
+
|
|
34
|
+
console.line()
|
|
35
|
+
console.print(Markdown("# Flock loaded...."), style="bold orange")
|
|
36
|
+
console.line()
|
|
37
|
+
|
|
38
|
+
flock.run()
|
flock/cli/settings.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# TODO
|
flock/config.py
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
# src/your_package/core/execution/local_executor.py
|
|
2
2
|
from flock.core.context.context import FlockContext
|
|
3
3
|
from flock.core.logging.logging import get_logger
|
|
4
|
-
from flock.workflow.activities import
|
|
4
|
+
from flock.workflow.activities import (
|
|
5
|
+
run_agent, # This should be the local activity function
|
|
6
|
+
)
|
|
5
7
|
|
|
6
8
|
logger = get_logger("flock")
|
|
7
9
|
|
|
8
10
|
|
|
9
|
-
async def run_local_workflow(
|
|
11
|
+
async def run_local_workflow(
|
|
12
|
+
context: FlockContext, box_result: bool = True
|
|
13
|
+
) -> dict:
|
|
10
14
|
"""Execute the agent workflow locally (for debugging).
|
|
11
15
|
|
|
12
16
|
Args:
|
|
@@ -18,7 +22,7 @@ async def run_local_workflow(context: FlockContext, output_formatter, box_result
|
|
|
18
22
|
A dictionary containing the workflow result.
|
|
19
23
|
"""
|
|
20
24
|
logger.info("Running local debug workflow")
|
|
21
|
-
result = await run_agent(context
|
|
25
|
+
result = await run_agent(context)
|
|
22
26
|
if box_result:
|
|
23
27
|
from box import Box
|
|
24
28
|
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
# src/your_package/core/execution/temporal_executor.py
|
|
2
|
-
from devtools import pprint
|
|
3
2
|
|
|
4
3
|
from flock.core.context.context import FlockContext
|
|
5
4
|
from flock.core.context.context_vars import FLOCK_RUN_ID
|
|
6
|
-
from flock.core.logging.formatters.formatter_factory import FormatterFactory
|
|
7
5
|
from flock.core.logging.logging import get_logger
|
|
8
6
|
from flock.workflow.activities import (
|
|
9
7
|
run_agent, # Activity function used in Temporal
|
|
@@ -16,7 +14,6 @@ logger = get_logger("flock")
|
|
|
16
14
|
|
|
17
15
|
async def run_temporal_workflow(
|
|
18
16
|
context: FlockContext,
|
|
19
|
-
output_formatter,
|
|
20
17
|
box_result: bool = True,
|
|
21
18
|
) -> dict:
|
|
22
19
|
"""Execute the agent workflow via Temporal for robust, distributed processing.
|
|
@@ -43,11 +40,7 @@ async def run_temporal_workflow(
|
|
|
43
40
|
|
|
44
41
|
agent_name = context.get_variable("FLOCK_CURRENT_AGENT")
|
|
45
42
|
logger.debug("Formatting Temporal result", agent=agent_name)
|
|
46
|
-
|
|
47
|
-
formatter = FormatterFactory.create_formatter(output_formatter)
|
|
48
|
-
formatter.display(result, agent_name, output_formatter.wait_for_input)
|
|
49
|
-
else:
|
|
50
|
-
pprint(result)
|
|
43
|
+
|
|
51
44
|
if box_result:
|
|
52
45
|
from box import Box
|
|
53
46
|
|
flock/core/flock.py
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
"""High-level orchestrator for creating and executing agents."""
|
|
2
2
|
|
|
3
|
+
import asyncio
|
|
4
|
+
import json
|
|
3
5
|
import os
|
|
4
6
|
import uuid
|
|
5
|
-
from typing import TypeVar
|
|
7
|
+
from typing import Any, TypeVar
|
|
6
8
|
|
|
9
|
+
import cloudpickle
|
|
7
10
|
from opentelemetry import trace
|
|
8
11
|
from opentelemetry.baggage import get_baggage, set_baggage
|
|
9
12
|
|
|
13
|
+
from flock.config import TELEMETRY
|
|
10
14
|
from flock.core.context.context import FlockContext
|
|
11
15
|
from flock.core.context.context_manager import initialize_context
|
|
12
16
|
from flock.core.execution.local_executor import run_local_workflow
|
|
13
17
|
from flock.core.execution.temporal_executor import run_temporal_workflow
|
|
14
18
|
from flock.core.flock_agent import FlockAgent
|
|
15
|
-
from flock.core.logging.formatters.base_formatter import FormatterOptions
|
|
16
|
-
from flock.core.logging.formatters.pprint_formatter import PrettyPrintFormatter
|
|
17
19
|
from flock.core.logging.logging import get_logger
|
|
18
20
|
from flock.core.registry.agent_registry import Registry
|
|
19
21
|
from flock.core.util.cli_helper import display_banner
|
|
@@ -21,7 +23,7 @@ from flock.core.util.input_resolver import top_level_to_keys
|
|
|
21
23
|
|
|
22
24
|
T = TypeVar("T", bound=FlockAgent)
|
|
23
25
|
logger = get_logger("flock")
|
|
24
|
-
|
|
26
|
+
TELEMETRY.setup_tracing()
|
|
25
27
|
tracer = trace.get_tracer(__name__)
|
|
26
28
|
|
|
27
29
|
|
|
@@ -37,9 +39,6 @@ class Flock:
|
|
|
37
39
|
model: str = "openai/gpt-4o",
|
|
38
40
|
local_debug: bool = False,
|
|
39
41
|
enable_logging: bool = False,
|
|
40
|
-
output_formatter: FormatterOptions = FormatterOptions(
|
|
41
|
-
PrettyPrintFormatter
|
|
42
|
-
),
|
|
43
42
|
show_cli_banner: bool = True,
|
|
44
43
|
):
|
|
45
44
|
"""Initialize the Flock orchestrator.
|
|
@@ -54,9 +53,6 @@ class Flock:
|
|
|
54
53
|
span.set_attribute("model", model)
|
|
55
54
|
span.set_attribute("local_debug", local_debug)
|
|
56
55
|
span.set_attribute("enable_logging", enable_logging)
|
|
57
|
-
span.set_attribute(
|
|
58
|
-
"output_formatter", output_formatter.formatter.__name__
|
|
59
|
-
)
|
|
60
56
|
logger.info(
|
|
61
57
|
"Initializing Flock",
|
|
62
58
|
model=model,
|
|
@@ -77,7 +73,8 @@ class Flock:
|
|
|
77
73
|
self.context = FlockContext()
|
|
78
74
|
self.model = model
|
|
79
75
|
self.local_debug = local_debug
|
|
80
|
-
self.
|
|
76
|
+
self.start_agent: FlockAgent | str | None = None
|
|
77
|
+
self.input: dict = {}
|
|
81
78
|
|
|
82
79
|
if local_debug:
|
|
83
80
|
os.environ["LOCAL_DEBUG"] = "1"
|
|
@@ -142,9 +139,173 @@ class Flock:
|
|
|
142
139
|
self.registry.register_tool(tool_name, tool)
|
|
143
140
|
logger.debug("Tool registered successfully")
|
|
144
141
|
|
|
142
|
+
def run(
|
|
143
|
+
self,
|
|
144
|
+
start_agent: FlockAgent | str | None = None,
|
|
145
|
+
input: dict = {},
|
|
146
|
+
context: FlockContext = None,
|
|
147
|
+
run_id: str = "",
|
|
148
|
+
box_result: bool = True,
|
|
149
|
+
) -> dict:
|
|
150
|
+
"""Entry point for running an agent system synchronously."""
|
|
151
|
+
return asyncio.run(
|
|
152
|
+
self.run_async(start_agent, input, context, run_id, box_result)
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
def save_to_file(
|
|
156
|
+
self,
|
|
157
|
+
file_path: str,
|
|
158
|
+
start_agent: str | None = None,
|
|
159
|
+
input: dict | None = None,
|
|
160
|
+
) -> None:
|
|
161
|
+
"""Save the Flock instance to a file.
|
|
162
|
+
|
|
163
|
+
This method serializes the Flock instance to a dictionary using the `to_dict()` method and saves it to a file.
|
|
164
|
+
The saved file can be reloaded later using the `from_file()` method.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
file_path (str): The path to the file where the Flock instance should be saved.
|
|
168
|
+
"""
|
|
169
|
+
hex_str = cloudpickle.dumps(self).hex()
|
|
170
|
+
|
|
171
|
+
result = {
|
|
172
|
+
"start_agent": start_agent,
|
|
173
|
+
"input": input,
|
|
174
|
+
"flock": hex_str,
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
path = os.path.dirname(file_path)
|
|
178
|
+
if path:
|
|
179
|
+
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
|
180
|
+
|
|
181
|
+
with open(file_path, "w") as file:
|
|
182
|
+
file.write(json.dumps(result))
|
|
183
|
+
|
|
184
|
+
@staticmethod
|
|
185
|
+
def load_from_file(file_path: str) -> "Flock":
|
|
186
|
+
"""Load a Flock instance from a file.
|
|
187
|
+
|
|
188
|
+
This class method deserializes a Flock instance from a file that was previously saved using the `save_to_file()`
|
|
189
|
+
method. It reads the file, converts the hexadecimal string back into a Flock instance, and returns it.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
file_path (str): The path to the file containing the serialized Flock instance.
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
Flock: A new Flock instance reconstructed from the saved file.
|
|
196
|
+
"""
|
|
197
|
+
with open(file_path) as file:
|
|
198
|
+
json_flock = json.load(file)
|
|
199
|
+
hex_str = json_flock["flock"]
|
|
200
|
+
flock = cloudpickle.loads(bytes.fromhex(hex_str))
|
|
201
|
+
if json_flock["start_agent"]:
|
|
202
|
+
agent = flock.registry.get_agent(json_flock["start_agent"])
|
|
203
|
+
flock.start_agent = agent
|
|
204
|
+
if json_flock["input"]:
|
|
205
|
+
flock.input = json_flock["input"]
|
|
206
|
+
return flock
|
|
207
|
+
|
|
208
|
+
def to_dict(self) -> dict[str, Any]:
|
|
209
|
+
"""Serialize the FlockAgent instance to a dictionary.
|
|
210
|
+
|
|
211
|
+
This method converts the entire agent instance—including its configuration, state, and lifecycle hooks—
|
|
212
|
+
into a dictionary format. It uses cloudpickle to serialize any callable objects (such as functions or
|
|
213
|
+
methods), converting them into hexadecimal string representations. This ensures that the agent can be
|
|
214
|
+
easily persisted, transmitted, or logged as JSON.
|
|
215
|
+
|
|
216
|
+
The serialization process is recursive:
|
|
217
|
+
- If a field is a callable (and not a class), it is serialized using cloudpickle.
|
|
218
|
+
- Lists and dictionaries are processed recursively to ensure that all nested callables are properly handled.
|
|
219
|
+
|
|
220
|
+
**Returns:**
|
|
221
|
+
dict[str, Any]: A dictionary representing the FlockAgent, which includes all of its configuration data.
|
|
222
|
+
This dictionary is suitable for storage, debugging, or transmission over the network.
|
|
223
|
+
|
|
224
|
+
**Example:**
|
|
225
|
+
For an agent defined as:
|
|
226
|
+
name = "idea_agent",
|
|
227
|
+
model = "openai/gpt-4o",
|
|
228
|
+
input = "query: str | The search query, context: dict | The full conversation context",
|
|
229
|
+
output = "idea: str | The generated idea"
|
|
230
|
+
Calling `agent.to_dict()` might produce:
|
|
231
|
+
{
|
|
232
|
+
"name": "idea_agent",
|
|
233
|
+
"model": "openai/gpt-4o",
|
|
234
|
+
"input": "query: str | The search query, context: dict | The full conversation context",
|
|
235
|
+
"output": "idea: str | The generated idea",
|
|
236
|
+
"tools": ["<serialized tool representation>"],
|
|
237
|
+
"use_cache": False,
|
|
238
|
+
"hand_off": None,
|
|
239
|
+
"termination": None,
|
|
240
|
+
...
|
|
241
|
+
}
|
|
242
|
+
"""
|
|
243
|
+
|
|
244
|
+
def convert_callable(obj: Any) -> Any:
|
|
245
|
+
if callable(obj) and not isinstance(obj, type):
|
|
246
|
+
return cloudpickle.dumps(obj).hex()
|
|
247
|
+
if isinstance(obj, list):
|
|
248
|
+
return [convert_callable(item) for item in obj]
|
|
249
|
+
if isinstance(obj, dict):
|
|
250
|
+
return {k: convert_callable(v) for k, v in obj.items()}
|
|
251
|
+
return obj
|
|
252
|
+
|
|
253
|
+
data = self.model_dump()
|
|
254
|
+
return convert_callable(data)
|
|
255
|
+
|
|
256
|
+
@classmethod
|
|
257
|
+
def from_dict(cls: type[T], data: dict[str, Any]) -> T:
|
|
258
|
+
"""Deserialize a FlockAgent instance from a dictionary.
|
|
259
|
+
|
|
260
|
+
This class method reconstructs a FlockAgent from its serialized dictionary representation, as produced
|
|
261
|
+
by the `to_dict()` method. It recursively processes the dictionary to convert any serialized callables
|
|
262
|
+
(stored as hexadecimal strings via cloudpickle) back into executable callable objects.
|
|
263
|
+
|
|
264
|
+
**Arguments:**
|
|
265
|
+
data (dict[str, Any]): A dictionary representation of a FlockAgent, typically produced by `to_dict()`.
|
|
266
|
+
The dictionary should contain all configuration fields and state information necessary to fully
|
|
267
|
+
reconstruct the agent.
|
|
268
|
+
|
|
269
|
+
**Returns:**
|
|
270
|
+
FlockAgent: An instance of FlockAgent reconstructed from the provided dictionary. The deserialized agent
|
|
271
|
+
will have the same configuration, state, and behavior as the original instance.
|
|
272
|
+
|
|
273
|
+
**Example:**
|
|
274
|
+
Suppose you have the following dictionary:
|
|
275
|
+
{
|
|
276
|
+
"name": "idea_agent",
|
|
277
|
+
"model": "openai/gpt-4o",
|
|
278
|
+
"input": "query: str | The search query, context: dict | The full conversation context",
|
|
279
|
+
"output": "idea: str | The generated idea",
|
|
280
|
+
"tools": ["<serialized tool representation>"],
|
|
281
|
+
"use_cache": False,
|
|
282
|
+
"hand_off": None,
|
|
283
|
+
"termination": None,
|
|
284
|
+
...
|
|
285
|
+
}
|
|
286
|
+
Then, calling:
|
|
287
|
+
agent = FlockAgent.from_dict(data)
|
|
288
|
+
will return a FlockAgent instance with the same properties and behavior as when it was originally serialized.
|
|
289
|
+
"""
|
|
290
|
+
|
|
291
|
+
def convert_callable(obj: Any) -> Any:
|
|
292
|
+
if isinstance(obj, str) and len(obj) > 2:
|
|
293
|
+
try:
|
|
294
|
+
return cloudpickle.loads(bytes.fromhex(obj))
|
|
295
|
+
except Exception:
|
|
296
|
+
return obj
|
|
297
|
+
if isinstance(obj, list):
|
|
298
|
+
return [convert_callable(item) for item in obj]
|
|
299
|
+
if isinstance(obj, dict):
|
|
300
|
+
return {k: convert_callable(v) for k, v in obj.items()}
|
|
301
|
+
return obj
|
|
302
|
+
|
|
303
|
+
converted = convert_callable(data)
|
|
304
|
+
return cls(**converted)
|
|
305
|
+
|
|
145
306
|
async def run_async(
|
|
146
307
|
self,
|
|
147
|
-
start_agent: FlockAgent | str,
|
|
308
|
+
start_agent: FlockAgent | str | None = None,
|
|
148
309
|
input: dict = {},
|
|
149
310
|
context: FlockContext = None,
|
|
150
311
|
run_id: str = "",
|
|
@@ -180,68 +341,70 @@ class Flock:
|
|
|
180
341
|
if hasattr(start_agent, "name")
|
|
181
342
|
else start_agent,
|
|
182
343
|
)
|
|
344
|
+
if start_agent:
|
|
345
|
+
self.start_agent = start_agent
|
|
346
|
+
if input:
|
|
347
|
+
self.input = input
|
|
183
348
|
|
|
184
|
-
span.set_attribute("input", str(input))
|
|
349
|
+
span.set_attribute("input", str(self.input))
|
|
185
350
|
span.set_attribute("context", str(context))
|
|
186
351
|
span.set_attribute("run_id", run_id)
|
|
187
352
|
span.set_attribute("box_result", box_result)
|
|
188
353
|
|
|
189
354
|
try:
|
|
190
|
-
if isinstance(start_agent, str):
|
|
355
|
+
if isinstance(self.start_agent, str):
|
|
191
356
|
logger.debug(
|
|
192
|
-
"Looking up agent by name", agent_name=start_agent
|
|
357
|
+
"Looking up agent by name", agent_name=self.start_agent
|
|
193
358
|
)
|
|
194
|
-
start_agent = self.registry.get_agent(start_agent)
|
|
195
|
-
if not start_agent:
|
|
196
|
-
logger.error(
|
|
359
|
+
self.start_agent = self.registry.get_agent(self.start_agent)
|
|
360
|
+
if not self.start_agent:
|
|
361
|
+
logger.error(
|
|
362
|
+
"Agent not found", agent_name=self.start_agent
|
|
363
|
+
)
|
|
197
364
|
raise ValueError(
|
|
198
|
-
f"Agent '{start_agent}' not found in registry"
|
|
365
|
+
f"Agent '{self.start_agent}' not found in registry"
|
|
199
366
|
)
|
|
200
|
-
start_agent.resolve_callables(context=self.context)
|
|
367
|
+
self.start_agent.resolve_callables(context=self.context)
|
|
201
368
|
if context:
|
|
202
369
|
logger.debug("Using provided context")
|
|
203
370
|
self.context = context
|
|
204
371
|
if not run_id:
|
|
205
|
-
run_id = f"{start_agent.name}_{uuid.uuid4().hex[:4]}"
|
|
372
|
+
run_id = f"{self.start_agent.name}_{uuid.uuid4().hex[:4]}"
|
|
206
373
|
logger.debug("Generated run ID", run_id=run_id)
|
|
207
374
|
|
|
208
375
|
set_baggage("run_id", run_id)
|
|
209
376
|
|
|
210
377
|
# TODO - Add a check for required input keys
|
|
211
|
-
input_keys = top_level_to_keys(start_agent.input)
|
|
378
|
+
input_keys = top_level_to_keys(self.start_agent.input)
|
|
212
379
|
for key in input_keys:
|
|
213
380
|
if key.startswith("flock."):
|
|
214
381
|
key = key[6:] # Remove the "flock." prefix
|
|
215
|
-
if key not in input:
|
|
382
|
+
if key not in self.input:
|
|
216
383
|
from rich.prompt import Prompt
|
|
217
384
|
|
|
218
|
-
input[key] = Prompt.ask(
|
|
219
|
-
f"Please enter {key} for {start_agent.name}"
|
|
385
|
+
self.input[key] = Prompt.ask(
|
|
386
|
+
f"Please enter {key} for {self.start_agent.name}"
|
|
220
387
|
)
|
|
221
388
|
|
|
222
389
|
# Initialize the context with standardized variables
|
|
223
390
|
initialize_context(
|
|
224
391
|
self.context,
|
|
225
|
-
start_agent.name,
|
|
226
|
-
input,
|
|
392
|
+
self.start_agent.name,
|
|
393
|
+
self.input,
|
|
227
394
|
run_id,
|
|
228
395
|
self.local_debug,
|
|
229
396
|
)
|
|
230
397
|
|
|
231
398
|
logger.info(
|
|
232
399
|
"Starting agent execution",
|
|
233
|
-
agent=start_agent.name,
|
|
400
|
+
agent=self.start_agent.name,
|
|
234
401
|
local_debug=self.local_debug,
|
|
235
402
|
)
|
|
236
403
|
|
|
237
404
|
if self.local_debug:
|
|
238
|
-
return await run_local_workflow(
|
|
239
|
-
self.context, self.output_formatter, box_result
|
|
240
|
-
)
|
|
405
|
+
return await run_local_workflow(self.context, box_result)
|
|
241
406
|
else:
|
|
242
|
-
return await run_temporal_workflow(
|
|
243
|
-
self.context, self.output_formatter, box_result
|
|
244
|
-
)
|
|
407
|
+
return await run_temporal_workflow(self.context, box_result)
|
|
245
408
|
except Exception as e:
|
|
246
409
|
logger.exception("Execution failed", error=str(e))
|
|
247
410
|
raise
|