flock-core 0.4.0b4__py3-none-any.whl → 0.4.0b6__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 +12 -0
- flock/cli/config.py +8 -0
- flock/cli/constants.py +11 -0
- flock/cli/create_flock.py +18 -6
- flock/cli/execute_flock.py +397 -1
- flock/cli/loaded_flock_cli.py +19 -4
- flock/cli/runner.py +41 -0
- flock/config.py +5 -0
- flock/core/api/endpoints.py +102 -2
- flock/core/api/main.py +214 -0
- flock/core/api/models.py +63 -0
- flock/core/api/run_store.py +153 -1
- flock/core/api/runner.py +38 -0
- flock/core/context/context_vars.py +1 -0
- flock/core/evaluation/utils.py +312 -0
- flock/core/execution/batch_executor.py +325 -0
- flock/core/execution/evaluation_executor.py +438 -0
- flock/core/flock.py +325 -1152
- flock/core/serialization/flock_serializer.py +717 -0
- flock/core/tools/azure_tools.py +2 -1
- flock/core/tools/basic_tools.py +1 -1
- flock/core/util/loader.py +59 -0
- flock/modules/output/output_module.py +43 -8
- {flock_core-0.4.0b4.dist-info → flock_core-0.4.0b6.dist-info}/METADATA +9 -1
- {flock_core-0.4.0b4.dist-info → flock_core-0.4.0b6.dist-info}/RECORD +28 -20
- {flock_core-0.4.0b4.dist-info → flock_core-0.4.0b6.dist-info}/WHEEL +0 -0
- {flock_core-0.4.0b4.dist-info → flock_core-0.4.0b6.dist-info}/entry_points.txt +0 -0
- {flock_core-0.4.0b4.dist-info → flock_core-0.4.0b6.dist-info}/licenses/LICENSE +0 -0
flock/__init__.py
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
from rich.panel import Panel
|
|
4
4
|
|
|
5
|
+
from flock.cli.config import init_config_file, load_config_file
|
|
5
6
|
from flock.cli.constants import (
|
|
7
|
+
CLI_CFG_FILE,
|
|
6
8
|
CLI_EXIT,
|
|
7
9
|
CLI_NOTES,
|
|
8
10
|
CLI_REGISTRY_MANAGEMENT,
|
|
@@ -35,6 +37,16 @@ def main():
|
|
|
35
37
|
# Show a welcome message on first run with the new tool serialization format
|
|
36
38
|
import os
|
|
37
39
|
|
|
40
|
+
cfg_file = os.path.expanduser(f"~/.flock/{CLI_CFG_FILE}")
|
|
41
|
+
if not os.path.exists(cfg_file):
|
|
42
|
+
# Create the directory if it doesn't exist
|
|
43
|
+
os.makedirs(os.path.dirname(cfg_file), exist_ok=True)
|
|
44
|
+
|
|
45
|
+
init_config_file()
|
|
46
|
+
else:
|
|
47
|
+
# Load the config file
|
|
48
|
+
load_config_file()
|
|
49
|
+
|
|
38
50
|
feature_flag_file = os.path.expanduser("~/.flock/tool_serialization_notice")
|
|
39
51
|
if not os.path.exists(feature_flag_file):
|
|
40
52
|
# Create the directory if it doesn't exist
|
flock/cli/config.py
ADDED
flock/cli/constants.py
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
"""Constants for the CLI module."""
|
|
2
2
|
|
|
3
|
+
CLI_CFG_FILE = ".env"
|
|
4
|
+
CLI_DEFAULT_ENV_VARS = {
|
|
5
|
+
"FLICK_API_KEY": "flock-api-key",
|
|
6
|
+
"FLICK_API_URL": "https://api.flock.com",
|
|
7
|
+
"FLICK_API_VERSION": "v1",
|
|
8
|
+
"FLICK_API_KEY": "flock-api-key",
|
|
9
|
+
"FLICK_API_URL": "https://api.flock.com",
|
|
10
|
+
"FLICK_API_VERSION": "v1",
|
|
11
|
+
}
|
|
12
|
+
CLI_DEFAULT_FOLDER = ".flock"
|
|
13
|
+
|
|
3
14
|
CLI_CREATE_AGENT = "Create an agent"
|
|
4
15
|
CLI_CREATE_FLOCK = "Create a new Flock"
|
|
5
16
|
CLI_LOAD_AGENT = "Load an agent"
|
flock/cli/create_flock.py
CHANGED
|
@@ -4,12 +4,14 @@ This module provides a wizard-like interface for creating new Flock instances,
|
|
|
4
4
|
with options for basic configuration and initial agent creation.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
from datetime import datetime
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
|
|
9
10
|
import questionary
|
|
10
11
|
from rich.console import Console
|
|
11
12
|
from rich.panel import Panel
|
|
12
13
|
|
|
14
|
+
from flock.cli.constants import CLI_DEFAULT_FOLDER
|
|
13
15
|
from flock.cli.loaded_flock_cli import start_loaded_flock_cli
|
|
14
16
|
from flock.core.flock import Flock
|
|
15
17
|
from flock.core.flock_factory import FlockFactory
|
|
@@ -31,6 +33,11 @@ def create_flock():
|
|
|
31
33
|
console.print("[bold]Step 1: Basic Flock Configuration[/]")
|
|
32
34
|
console.line()
|
|
33
35
|
|
|
36
|
+
flock_name = questionary.text(
|
|
37
|
+
"Enter a name for this Flock:",
|
|
38
|
+
default="",
|
|
39
|
+
).ask()
|
|
40
|
+
|
|
34
41
|
# Get description
|
|
35
42
|
description = questionary.text(
|
|
36
43
|
"Enter a description for this Flock (optional):",
|
|
@@ -61,10 +68,11 @@ def create_flock():
|
|
|
61
68
|
model = model_choice
|
|
62
69
|
|
|
63
70
|
# Execution options
|
|
64
|
-
enable_temporal = questionary.confirm(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
).ask()
|
|
71
|
+
# enable_temporal = questionary.confirm(
|
|
72
|
+
# "Enable Temporal for distributed execution?",
|
|
73
|
+
# default=False,
|
|
74
|
+
# ).ask()
|
|
75
|
+
enable_temporal = False
|
|
68
76
|
|
|
69
77
|
# Logging configuration
|
|
70
78
|
enable_logging = questionary.confirm(
|
|
@@ -74,6 +82,7 @@ def create_flock():
|
|
|
74
82
|
|
|
75
83
|
# Create the Flock instance
|
|
76
84
|
flock = Flock(
|
|
85
|
+
name=flock_name,
|
|
77
86
|
model=model,
|
|
78
87
|
description=description,
|
|
79
88
|
enable_temporal=enable_temporal,
|
|
@@ -200,7 +209,8 @@ def _save_flock_to_yaml(flock):
|
|
|
200
209
|
flock: The Flock instance to save
|
|
201
210
|
"""
|
|
202
211
|
# Get file path
|
|
203
|
-
|
|
212
|
+
# default = flock.name + current date in 04_04_2025 format
|
|
213
|
+
default_name = f"{flock.name}_{datetime.now().strftime('%m_%d_%Y')}"
|
|
204
214
|
file_path = questionary.text(
|
|
205
215
|
"Enter file path to save Flock:",
|
|
206
216
|
default=default_name,
|
|
@@ -208,7 +218,9 @@ def _save_flock_to_yaml(flock):
|
|
|
208
218
|
|
|
209
219
|
# Ensure the file has the correct extension
|
|
210
220
|
if not file_path.endswith((".yaml", ".yml")):
|
|
211
|
-
file_path += ".yaml"
|
|
221
|
+
file_path += ".flock.yaml"
|
|
222
|
+
|
|
223
|
+
file_path = CLI_DEFAULT_FOLDER + "/" + file_path
|
|
212
224
|
|
|
213
225
|
# Create directory if it doesn't exist
|
|
214
226
|
save_path = Path(file_path)
|
flock/cli/execute_flock.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"""Execute a Flock instance with a selected agent.
|
|
2
2
|
|
|
3
3
|
This module provides functionality to execute a Flock instance with
|
|
4
|
-
a selected agent and input configuration.
|
|
4
|
+
a selected agent and input configuration, including batch processing.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import json
|
|
8
|
+
import os
|
|
8
9
|
|
|
9
10
|
import questionary
|
|
10
11
|
from rich.console import Console
|
|
@@ -16,6 +17,15 @@ from flock.core.util.cli_helper import init_console
|
|
|
16
17
|
# Create console instance
|
|
17
18
|
console = Console()
|
|
18
19
|
|
|
20
|
+
# Try importing pandas for DataFrame support
|
|
21
|
+
try:
|
|
22
|
+
import pandas as pd
|
|
23
|
+
|
|
24
|
+
PANDAS_AVAILABLE = True
|
|
25
|
+
except ImportError:
|
|
26
|
+
pd = None
|
|
27
|
+
PANDAS_AVAILABLE = False
|
|
28
|
+
|
|
19
29
|
|
|
20
30
|
def execute_flock(flock: Flock):
|
|
21
31
|
"""Execute a Flock instance.
|
|
@@ -198,3 +208,389 @@ def _parse_input_schema(input_schema: str) -> dict[str, dict[str, str]]:
|
|
|
198
208
|
return {}
|
|
199
209
|
|
|
200
210
|
return fields
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def execute_flock_batch(flock: Flock):
|
|
214
|
+
"""Execute a Flock instance in batch mode.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
flock: The Flock instance to execute
|
|
218
|
+
"""
|
|
219
|
+
if not flock:
|
|
220
|
+
console.print("[bold red]Error: No Flock instance provided.[/]")
|
|
221
|
+
return
|
|
222
|
+
|
|
223
|
+
agent_names = list(flock._agents.keys())
|
|
224
|
+
|
|
225
|
+
if not agent_names:
|
|
226
|
+
console.print("[yellow]No agents in this Flock to execute.[/]")
|
|
227
|
+
return
|
|
228
|
+
|
|
229
|
+
init_console()
|
|
230
|
+
console.print(
|
|
231
|
+
Panel("[bold green]Execute Flock - Batch Mode[/]"), justify="center"
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
# Step 1: Select start agent
|
|
235
|
+
console.print("\n[bold]Step 1: Select Start Agent[/]")
|
|
236
|
+
|
|
237
|
+
start_agent_name = questionary.select(
|
|
238
|
+
"Select an agent to start with:",
|
|
239
|
+
choices=agent_names,
|
|
240
|
+
).ask()
|
|
241
|
+
|
|
242
|
+
if not start_agent_name:
|
|
243
|
+
return
|
|
244
|
+
|
|
245
|
+
start_agent = flock._agents[start_agent_name]
|
|
246
|
+
|
|
247
|
+
# Step 2: Configure batch input source
|
|
248
|
+
console.print("\n[bold]Step 2: Select Batch Input Source[/]")
|
|
249
|
+
|
|
250
|
+
if not PANDAS_AVAILABLE:
|
|
251
|
+
console.print(
|
|
252
|
+
"[yellow]Warning: pandas not available. CSV input/output functionality will be limited.[/]"
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
input_source_choices = ["Enter batch items manually"]
|
|
256
|
+
|
|
257
|
+
if PANDAS_AVAILABLE:
|
|
258
|
+
input_source_choices.insert(0, "Load from CSV file")
|
|
259
|
+
|
|
260
|
+
input_source = questionary.select(
|
|
261
|
+
"How would you like to provide batch inputs?",
|
|
262
|
+
choices=input_source_choices,
|
|
263
|
+
).ask()
|
|
264
|
+
|
|
265
|
+
if not input_source:
|
|
266
|
+
return
|
|
267
|
+
|
|
268
|
+
batch_inputs = []
|
|
269
|
+
input_mapping = {}
|
|
270
|
+
|
|
271
|
+
if input_source == "Load from CSV file" and PANDAS_AVAILABLE:
|
|
272
|
+
# Ask for CSV file path
|
|
273
|
+
csv_path = questionary.path(
|
|
274
|
+
"Enter path to CSV file:",
|
|
275
|
+
).ask()
|
|
276
|
+
|
|
277
|
+
if not csv_path:
|
|
278
|
+
return
|
|
279
|
+
|
|
280
|
+
try:
|
|
281
|
+
# Validate path exists
|
|
282
|
+
if not os.path.exists(csv_path):
|
|
283
|
+
console.print(
|
|
284
|
+
f"[bold red]Error: File '{csv_path}' does not exist.[/]"
|
|
285
|
+
)
|
|
286
|
+
return
|
|
287
|
+
|
|
288
|
+
# Preview CSV
|
|
289
|
+
df = pd.read_csv(csv_path)
|
|
290
|
+
console.print("\n[bold]CSV Preview (first 5 rows):[/]")
|
|
291
|
+
console.print(df.head().to_string())
|
|
292
|
+
|
|
293
|
+
# Configure column mapping
|
|
294
|
+
console.print("\n[bold]Configure Column Mapping:[/]")
|
|
295
|
+
|
|
296
|
+
# Parse input schema (if available)
|
|
297
|
+
input_fields = _parse_input_schema(start_agent.input)
|
|
298
|
+
|
|
299
|
+
# If we have input fields, map CSV columns to them
|
|
300
|
+
if input_fields:
|
|
301
|
+
columns = df.columns.tolist()
|
|
302
|
+
|
|
303
|
+
for field in input_fields.keys():
|
|
304
|
+
field_desc = input_fields[field].get("description", "")
|
|
305
|
+
prompt = f"Select column for '{field}'"
|
|
306
|
+
|
|
307
|
+
if field_desc:
|
|
308
|
+
prompt += f" ({field_desc})"
|
|
309
|
+
|
|
310
|
+
selected_col = questionary.select(
|
|
311
|
+
prompt,
|
|
312
|
+
choices=["(Skip this field)"] + columns,
|
|
313
|
+
).ask()
|
|
314
|
+
|
|
315
|
+
if selected_col and selected_col != "(Skip this field)":
|
|
316
|
+
input_mapping[selected_col] = field
|
|
317
|
+
else:
|
|
318
|
+
# No schema, ask user to map columns manually
|
|
319
|
+
columns = df.columns.tolist()
|
|
320
|
+
|
|
321
|
+
for col in columns:
|
|
322
|
+
mapping = questionary.text(
|
|
323
|
+
f"Map column '{col}' to input field (leave empty to ignore):",
|
|
324
|
+
).ask()
|
|
325
|
+
|
|
326
|
+
if mapping:
|
|
327
|
+
input_mapping[col] = mapping
|
|
328
|
+
|
|
329
|
+
if not input_mapping:
|
|
330
|
+
console.print("[yellow]Warning: No column mapping defined.[/]")
|
|
331
|
+
if not questionary.confirm(
|
|
332
|
+
"Continue without mapping?", default=False
|
|
333
|
+
).ask():
|
|
334
|
+
return
|
|
335
|
+
|
|
336
|
+
# Use the CSV file path directly
|
|
337
|
+
batch_inputs = csv_path
|
|
338
|
+
|
|
339
|
+
except Exception as e:
|
|
340
|
+
console.print(f"[bold red]Error loading CSV: {e}[/]")
|
|
341
|
+
return
|
|
342
|
+
|
|
343
|
+
elif input_source == "Enter batch items manually":
|
|
344
|
+
# Parse input schema
|
|
345
|
+
input_fields = _parse_input_schema(start_agent.input)
|
|
346
|
+
|
|
347
|
+
if not input_fields:
|
|
348
|
+
console.print(
|
|
349
|
+
"[yellow]No input schema available. Using JSON input.[/]"
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
while True:
|
|
353
|
+
raw_input = questionary.text(
|
|
354
|
+
"Enter batch item as JSON (empty to finish):",
|
|
355
|
+
default="{}",
|
|
356
|
+
).ask()
|
|
357
|
+
|
|
358
|
+
if not raw_input:
|
|
359
|
+
break
|
|
360
|
+
|
|
361
|
+
try:
|
|
362
|
+
item_data = json.loads(raw_input)
|
|
363
|
+
batch_inputs.append(item_data)
|
|
364
|
+
console.print(f"[green]Added item {len(batch_inputs)}[/]")
|
|
365
|
+
except json.JSONDecodeError:
|
|
366
|
+
console.print("[bold red]Error: Invalid JSON input.[/]")
|
|
367
|
+
|
|
368
|
+
else:
|
|
369
|
+
# We have input fields, ask for each field for each item
|
|
370
|
+
item_count = 1
|
|
371
|
+
|
|
372
|
+
while True:
|
|
373
|
+
console.print(f"\n[bold]Batch Item {item_count}[/]")
|
|
374
|
+
|
|
375
|
+
item_data = {}
|
|
376
|
+
for field, info in input_fields.items():
|
|
377
|
+
field_type = info.get("type", "str")
|
|
378
|
+
description = info.get("description", "")
|
|
379
|
+
prompt = f"Enter value for '{field}'"
|
|
380
|
+
|
|
381
|
+
if description:
|
|
382
|
+
prompt += f" ({description})"
|
|
383
|
+
|
|
384
|
+
prompt += " (empty to skip):"
|
|
385
|
+
|
|
386
|
+
value = questionary.text(prompt).ask()
|
|
387
|
+
|
|
388
|
+
if not value:
|
|
389
|
+
continue
|
|
390
|
+
|
|
391
|
+
# Convert value to appropriate type
|
|
392
|
+
if field_type == "int":
|
|
393
|
+
try:
|
|
394
|
+
value = int(value)
|
|
395
|
+
except ValueError:
|
|
396
|
+
console.print(
|
|
397
|
+
f"[yellow]Warning: Could not convert value to int, using as string.[/]"
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
item_data[field] = value
|
|
401
|
+
|
|
402
|
+
if item_data:
|
|
403
|
+
batch_inputs.append(item_data)
|
|
404
|
+
console.print(f"[green]Added item {len(batch_inputs)}[/]")
|
|
405
|
+
|
|
406
|
+
if not questionary.confirm(
|
|
407
|
+
"Add another batch item?",
|
|
408
|
+
default=len(batch_inputs)
|
|
409
|
+
< 2, # Default to yes if we have less than 2 items
|
|
410
|
+
).ask():
|
|
411
|
+
break
|
|
412
|
+
|
|
413
|
+
item_count += 1
|
|
414
|
+
|
|
415
|
+
if isinstance(batch_inputs, list) and not batch_inputs:
|
|
416
|
+
console.print("[yellow]No batch items defined. Exiting.[/]")
|
|
417
|
+
return
|
|
418
|
+
|
|
419
|
+
# Step 3: Configure static inputs (if needed)
|
|
420
|
+
static_inputs = {}
|
|
421
|
+
|
|
422
|
+
if questionary.confirm(
|
|
423
|
+
"Would you like to add static inputs (common to all batch items)?",
|
|
424
|
+
default=False,
|
|
425
|
+
).ask():
|
|
426
|
+
console.print("\n[bold]Configure Static Inputs[/]")
|
|
427
|
+
|
|
428
|
+
raw_static = questionary.text(
|
|
429
|
+
"Enter static inputs as JSON:",
|
|
430
|
+
default="{}",
|
|
431
|
+
).ask()
|
|
432
|
+
|
|
433
|
+
try:
|
|
434
|
+
static_inputs = json.loads(raw_static)
|
|
435
|
+
except json.JSONDecodeError:
|
|
436
|
+
console.print(
|
|
437
|
+
"[bold red]Error: Invalid JSON for static inputs. Proceeding without static inputs.[/]"
|
|
438
|
+
)
|
|
439
|
+
static_inputs = {}
|
|
440
|
+
|
|
441
|
+
# Step 4: Configure batch execution options
|
|
442
|
+
console.print("\n[bold]Step 4: Configure Batch Execution Options[/]")
|
|
443
|
+
|
|
444
|
+
# Determine if we should use Temporal
|
|
445
|
+
use_temporal = False
|
|
446
|
+
# if questionary.confirm(
|
|
447
|
+
# f"Override Temporal setting? (Current: {flock.enable_temporal})",
|
|
448
|
+
# default=False,
|
|
449
|
+
# ).ask():
|
|
450
|
+
# use_temporal = questionary.confirm(
|
|
451
|
+
# "Use Temporal for batch execution?",
|
|
452
|
+
# default=flock.enable_temporal,
|
|
453
|
+
# ).ask()
|
|
454
|
+
|
|
455
|
+
# Configure parallelism
|
|
456
|
+
parallel = True
|
|
457
|
+
max_workers = 5
|
|
458
|
+
|
|
459
|
+
if not flock.enable_temporal if use_temporal is None else not use_temporal:
|
|
460
|
+
parallel = questionary.confirm(
|
|
461
|
+
"Run batch items in parallel?",
|
|
462
|
+
default=True,
|
|
463
|
+
).ask()
|
|
464
|
+
|
|
465
|
+
if parallel:
|
|
466
|
+
max_workers_input = questionary.text(
|
|
467
|
+
"Maximum number of parallel workers:",
|
|
468
|
+
default="5",
|
|
469
|
+
).ask()
|
|
470
|
+
|
|
471
|
+
try:
|
|
472
|
+
max_workers = int(max_workers_input)
|
|
473
|
+
except ValueError:
|
|
474
|
+
console.print(
|
|
475
|
+
"[yellow]Invalid worker count. Using default (5).[/]"
|
|
476
|
+
)
|
|
477
|
+
max_workers = 5
|
|
478
|
+
|
|
479
|
+
# Configure output options
|
|
480
|
+
silent_mode = questionary.confirm(
|
|
481
|
+
"Use silent mode with progress bar? (Recommended for large batches)",
|
|
482
|
+
default=True,
|
|
483
|
+
).ask()
|
|
484
|
+
|
|
485
|
+
write_to_csv = None
|
|
486
|
+
if (
|
|
487
|
+
PANDAS_AVAILABLE
|
|
488
|
+
and questionary.confirm(
|
|
489
|
+
"Write results to CSV file?",
|
|
490
|
+
default=True,
|
|
491
|
+
).ask()
|
|
492
|
+
):
|
|
493
|
+
write_to_csv = questionary.text(
|
|
494
|
+
"CSV output path:",
|
|
495
|
+
default="batch_results.csv",
|
|
496
|
+
).ask()
|
|
497
|
+
|
|
498
|
+
# Logging options
|
|
499
|
+
enable_logging = questionary.confirm(
|
|
500
|
+
"Enable detailed logging?",
|
|
501
|
+
default=False,
|
|
502
|
+
).ask()
|
|
503
|
+
|
|
504
|
+
# Preview configuration
|
|
505
|
+
console.print("\n[bold]Batch Configuration Preview:[/]")
|
|
506
|
+
console.print(f"Agent: {start_agent_name}")
|
|
507
|
+
|
|
508
|
+
if isinstance(batch_inputs, str):
|
|
509
|
+
console.print(f"Input Source: CSV file ({batch_inputs})")
|
|
510
|
+
console.print(f"Column Mapping: {input_mapping}")
|
|
511
|
+
else:
|
|
512
|
+
console.print(f"Input Source: Manual entry ({len(batch_inputs)} items)")
|
|
513
|
+
|
|
514
|
+
if static_inputs:
|
|
515
|
+
console.print(f"Static Inputs: {json.dumps(static_inputs, indent=2)}")
|
|
516
|
+
|
|
517
|
+
# temporal_status = (
|
|
518
|
+
# "Default" if use_temporal is None else ("Yes" if use_temporal else "No")
|
|
519
|
+
# )
|
|
520
|
+
# console.print(f"Use Temporal: {temporal_status}")
|
|
521
|
+
|
|
522
|
+
if not (flock.enable_temporal if use_temporal is None else use_temporal):
|
|
523
|
+
console.print(f"Parallel Execution: {parallel}")
|
|
524
|
+
if parallel:
|
|
525
|
+
console.print(f"Max Workers: {max_workers}")
|
|
526
|
+
|
|
527
|
+
console.print(f"Silent Mode: {silent_mode}")
|
|
528
|
+
|
|
529
|
+
if write_to_csv:
|
|
530
|
+
console.print(f"Write Results to: {write_to_csv}")
|
|
531
|
+
|
|
532
|
+
# Confirm execution
|
|
533
|
+
confirm = questionary.confirm(
|
|
534
|
+
"Execute batch with this configuration?",
|
|
535
|
+
default=True,
|
|
536
|
+
).ask()
|
|
537
|
+
|
|
538
|
+
if not confirm:
|
|
539
|
+
return
|
|
540
|
+
|
|
541
|
+
# Execute the batch
|
|
542
|
+
console.print("\n[bold]Executing Batch...[/]")
|
|
543
|
+
|
|
544
|
+
try:
|
|
545
|
+
# Handle logging settings
|
|
546
|
+
if enable_logging:
|
|
547
|
+
flock._configure_logging(True)
|
|
548
|
+
|
|
549
|
+
# Run the batch
|
|
550
|
+
results = flock.run_batch(
|
|
551
|
+
start_agent=start_agent_name,
|
|
552
|
+
batch_inputs=batch_inputs,
|
|
553
|
+
input_mapping=input_mapping or None,
|
|
554
|
+
static_inputs=static_inputs or None,
|
|
555
|
+
parallel=parallel,
|
|
556
|
+
max_workers=max_workers,
|
|
557
|
+
use_temporal=use_temporal,
|
|
558
|
+
box_results=True,
|
|
559
|
+
return_errors=True,
|
|
560
|
+
silent_mode=silent_mode,
|
|
561
|
+
write_to_csv=write_to_csv,
|
|
562
|
+
)
|
|
563
|
+
|
|
564
|
+
# Display results summary
|
|
565
|
+
console.print("\n[bold green]Batch Execution Complete![/]")
|
|
566
|
+
|
|
567
|
+
success_count = sum(1 for r in results if not isinstance(r, Exception))
|
|
568
|
+
error_count = sum(1 for r in results if isinstance(r, Exception))
|
|
569
|
+
|
|
570
|
+
console.print(f"Total Items: {len(results)}")
|
|
571
|
+
console.print(f"Successful: {success_count}")
|
|
572
|
+
|
|
573
|
+
if error_count > 0:
|
|
574
|
+
console.print(f"[bold red]Errors: {error_count}[/]")
|
|
575
|
+
|
|
576
|
+
# Ask if user wants to see detailed results
|
|
577
|
+
if questionary.confirm(
|
|
578
|
+
"View detailed results?",
|
|
579
|
+
default=False,
|
|
580
|
+
).ask():
|
|
581
|
+
for i, result in enumerate(results):
|
|
582
|
+
console.print(f"\n[bold]Item {i + 1}:[/]")
|
|
583
|
+
if isinstance(result, Exception):
|
|
584
|
+
console.print(f"[bold red]Error: {result}[/]")
|
|
585
|
+
else:
|
|
586
|
+
# Display as formatted JSON
|
|
587
|
+
try:
|
|
588
|
+
console.print(json.dumps(result, indent=2))
|
|
589
|
+
except:
|
|
590
|
+
console.print(str(result))
|
|
591
|
+
|
|
592
|
+
if write_to_csv:
|
|
593
|
+
console.print(f"\n[green]Results written to: {write_to_csv}[/]")
|
|
594
|
+
|
|
595
|
+
except Exception as e:
|
|
596
|
+
console.print(f"\n[bold red]Error during batch execution:[/] {e!s}")
|
flock/cli/loaded_flock_cli.py
CHANGED
|
@@ -12,6 +12,7 @@ from flock.cli.constants import (
|
|
|
12
12
|
CLI_REGISTRY_MANAGEMENT,
|
|
13
13
|
CLI_SETTINGS,
|
|
14
14
|
)
|
|
15
|
+
from flock.core.api import runner
|
|
15
16
|
from flock.core.flock import Flock
|
|
16
17
|
from flock.core.util.cli_helper import init_console
|
|
17
18
|
|
|
@@ -32,7 +33,7 @@ except ImportError:
|
|
|
32
33
|
manage_agents_available = False
|
|
33
34
|
|
|
34
35
|
try:
|
|
35
|
-
from flock.cli.execute_flock import execute_flock
|
|
36
|
+
from flock.cli.execute_flock import execute_flock, execute_flock_batch
|
|
36
37
|
|
|
37
38
|
execute_flock_available = True
|
|
38
39
|
except ImportError:
|
|
@@ -94,6 +95,7 @@ def start_loaded_flock_cli(
|
|
|
94
95
|
choices = [
|
|
95
96
|
questionary.Separator(line=" "),
|
|
96
97
|
"Execute Flock",
|
|
98
|
+
"Execute Flock - Batch Mode",
|
|
97
99
|
"Start Web Server",
|
|
98
100
|
"Start Web Server with UI",
|
|
99
101
|
"Manage Agents",
|
|
@@ -131,6 +133,15 @@ def start_loaded_flock_cli(
|
|
|
131
133
|
)
|
|
132
134
|
input("\nPress Enter to continue...")
|
|
133
135
|
|
|
136
|
+
elif choice == "Execute Flock - Batch Mode":
|
|
137
|
+
if execute_flock_available:
|
|
138
|
+
execute_flock_batch(flock)
|
|
139
|
+
else:
|
|
140
|
+
console.print(
|
|
141
|
+
"[yellow]Batch execution functionality not yet implemented.[/]"
|
|
142
|
+
)
|
|
143
|
+
input("\nPress Enter to continue...")
|
|
144
|
+
|
|
134
145
|
elif choice == "Start Web Server":
|
|
135
146
|
_start_web_server(flock, create_ui=False)
|
|
136
147
|
|
|
@@ -203,7 +214,7 @@ def _start_web_server(flock: Flock, create_ui: bool = False) -> None:
|
|
|
203
214
|
port = int(port_input)
|
|
204
215
|
|
|
205
216
|
server_name_input = questionary.text(
|
|
206
|
-
"Server name (default:
|
|
217
|
+
"Server name (default: FlockName API):", default=flock.name + " API"
|
|
207
218
|
).ask()
|
|
208
219
|
if server_name_input:
|
|
209
220
|
server_name = server_name_input
|
|
@@ -214,6 +225,10 @@ def _start_web_server(flock: Flock, create_ui: bool = False) -> None:
|
|
|
214
225
|
)
|
|
215
226
|
|
|
216
227
|
# Use the Flock's start_api method
|
|
217
|
-
|
|
218
|
-
|
|
228
|
+
runner.start_flock_api(
|
|
229
|
+
flock=flock,
|
|
230
|
+
host=host,
|
|
231
|
+
port=port,
|
|
232
|
+
server_name=server_name,
|
|
233
|
+
create_ui=create_ui,
|
|
219
234
|
)
|
flock/cli/runner.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# src/flock/cli/runner.py
|
|
2
|
+
"""Provides functionality to start the Flock CLI."""
|
|
3
|
+
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from flock.core.logging.logging import get_logger
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from flock.core.flock import Flock
|
|
10
|
+
|
|
11
|
+
logger = get_logger("cli.runner")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def start_flock_cli(
|
|
15
|
+
flock: Flock,
|
|
16
|
+
server_name: str = "Flock CLI",
|
|
17
|
+
show_results: bool = False,
|
|
18
|
+
edit_mode: bool = False,
|
|
19
|
+
) -> None:
|
|
20
|
+
"""Start a CLI interface for the given Flock instance."""
|
|
21
|
+
try:
|
|
22
|
+
# Import CLI function locally
|
|
23
|
+
from flock.cli.loaded_flock_cli import start_loaded_flock_cli
|
|
24
|
+
except ImportError:
|
|
25
|
+
logger.error(
|
|
26
|
+
"CLI components not found. Cannot start CLI. "
|
|
27
|
+
"Ensure the CLI modules are properly installed/available."
|
|
28
|
+
)
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
logger.info(
|
|
32
|
+
f"Starting CLI interface for loaded Flock instance '{flock.name}' ({len(flock.agents)} agents)"
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
# Pass the Flock instance to the CLI entry point
|
|
36
|
+
start_loaded_flock_cli(
|
|
37
|
+
flock=flock,
|
|
38
|
+
server_name=server_name,
|
|
39
|
+
show_results=show_results,
|
|
40
|
+
edit_mode=edit_mode,
|
|
41
|
+
)
|
flock/config.py
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
# flock/config.py
|
|
2
|
+
import os
|
|
3
|
+
|
|
2
4
|
from decouple import config
|
|
3
5
|
|
|
4
6
|
from flock.core.logging.telemetry import TelemetryConfig
|
|
5
7
|
|
|
8
|
+
cfg_file = os.path.expanduser(f"~/.flock/flock.cfg")
|
|
9
|
+
|
|
10
|
+
|
|
6
11
|
# -- Connection and External Service Configurations --
|
|
7
12
|
TEMPORAL_SERVER_URL = config("TEMPORAL_SERVER_URL", "localhost:7233")
|
|
8
13
|
DEFAULT_MODEL = config("DEFAULT_MODEL", "openai/gpt-4o")
|