flock-core 0.3.30__py3-none-any.whl → 0.3.32__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.

@@ -0,0 +1,202 @@
1
+ """CLI interface for working with a loaded Flock instance.
2
+
3
+ This module provides a CLI interface for a Flock instance that has already been loaded,
4
+ allowing users to execute, edit, or manage agents from the existing configuration.
5
+ """
6
+
7
+ import questionary
8
+ from rich.console import Console
9
+ from rich.panel import Panel
10
+
11
+ from flock.core.flock import Flock
12
+ from flock.core.util.cli_helper import init_console
13
+
14
+ # Import future modules we'll create
15
+ # These will be implemented later
16
+ try:
17
+ from flock.cli.yaml_editor import yaml_editor
18
+
19
+ yaml_editor_available = True
20
+ except ImportError:
21
+ yaml_editor_available = False
22
+
23
+ try:
24
+ from flock.cli.manage_agents import manage_agents
25
+
26
+ manage_agents_available = True
27
+ except ImportError:
28
+ manage_agents_available = False
29
+
30
+ try:
31
+ from flock.cli.execute_flock import execute_flock
32
+
33
+ execute_flock_available = True
34
+ except ImportError:
35
+ execute_flock_available = False
36
+
37
+ try:
38
+ from flock.cli.view_results import view_results
39
+
40
+ view_results_available = True
41
+ except ImportError:
42
+ view_results_available = False
43
+
44
+ # Create console instance
45
+ console = Console()
46
+
47
+
48
+ def start_loaded_flock_cli(
49
+ flock: Flock,
50
+ server_name: str = "Flock CLI",
51
+ show_results: bool = False,
52
+ edit_mode: bool = False,
53
+ ) -> None:
54
+ """Start a CLI interface with a loaded Flock instance.
55
+
56
+ Args:
57
+ flock: The loaded Flock instance
58
+ server_name: Optional name for the CLI interface
59
+ show_results: Whether to initially show results of previous runs
60
+ edit_mode: Whether to open directly in edit mode
61
+ """
62
+ if not flock:
63
+ console.print("[bold red]Error: No Flock instance provided.[/]")
64
+ return
65
+
66
+ agent_names = list(flock._agents.keys())
67
+
68
+ # Directly go to specific modes if requested
69
+ if edit_mode and yaml_editor_available:
70
+ yaml_editor(flock)
71
+ return
72
+
73
+ if show_results and view_results_available:
74
+ view_results(flock)
75
+ return
76
+
77
+ # Main CLI loop
78
+ while True:
79
+ # Initialize console for each loop iteration
80
+ init_console()
81
+
82
+ # Display header with Flock information
83
+ console.print(Panel(f"[bold green]{server_name}[/]"), justify="center")
84
+ console.print(
85
+ f"Flock loaded with [bold cyan]{len(agent_names)}[/] agents: {', '.join(agent_names)}"
86
+ )
87
+ console.line()
88
+
89
+ # Main menu choices
90
+ choices = [
91
+ questionary.Separator(line=" "),
92
+ "Execute Flock",
93
+ "Start Web Server",
94
+ "Start Web Server with UI",
95
+ "Manage Agents",
96
+ "View Results of Past Runs",
97
+ ]
98
+
99
+ # Add YAML Editor option if available
100
+ if yaml_editor_available:
101
+ choices.append("Edit YAML Configurations")
102
+
103
+ # Add remaining options
104
+ choices.extend([questionary.Separator(), "Settings", "Exit"])
105
+
106
+ # Display menu and get choice
107
+ choice = questionary.select(
108
+ "What would you like to do?",
109
+ choices=choices,
110
+ ).ask()
111
+
112
+ # Handle menu selection
113
+ if choice == "Execute Flock":
114
+ if execute_flock_available:
115
+ execute_flock(flock)
116
+ else:
117
+ console.print(
118
+ "[yellow]Execute Flock functionality not yet implemented.[/]"
119
+ )
120
+ input("\nPress Enter to continue...")
121
+
122
+ elif choice == "Start Web Server":
123
+ _start_web_server(flock, create_ui=False)
124
+
125
+ elif choice == "Start Web Server with UI":
126
+ _start_web_server(flock, create_ui=True)
127
+
128
+ elif choice == "Manage Agents":
129
+ if manage_agents_available:
130
+ manage_agents(flock)
131
+ else:
132
+ console.print(
133
+ "[yellow]Manage Agents functionality not yet implemented.[/]"
134
+ )
135
+ input("\nPress Enter to continue...")
136
+
137
+ elif choice == "View Results of Past Runs":
138
+ if view_results_available:
139
+ view_results(flock)
140
+ else:
141
+ console.print(
142
+ "[yellow]View Results functionality not yet implemented.[/]"
143
+ )
144
+ input("\nPress Enter to continue...")
145
+
146
+ elif choice == "Edit YAML Configurations" and yaml_editor_available:
147
+ yaml_editor(flock)
148
+
149
+ elif choice == "Settings":
150
+ from flock.cli.settings import settings_editor
151
+
152
+ settings_editor()
153
+
154
+ elif choice == "Exit":
155
+ break
156
+
157
+ # Pause after each action unless we're exiting
158
+ if choice != "Exit" and not choice.startswith("Start Web Server"):
159
+ input("\nPress Enter to continue...")
160
+
161
+
162
+ def _start_web_server(flock: Flock, create_ui: bool = False) -> None:
163
+ """Start a web server with the loaded Flock instance.
164
+
165
+ Args:
166
+ flock: The loaded Flock instance
167
+ create_ui: Whether to create a UI for the web server
168
+ """
169
+ host = "127.0.0.1"
170
+ port = 8344
171
+ server_name = "Flock API"
172
+
173
+ # Get configuration from user
174
+ console.print("\n[bold]Web Server Configuration[/]")
175
+
176
+ host_input = questionary.text(
177
+ "Host (default: 127.0.0.1):", default=host
178
+ ).ask()
179
+ if host_input:
180
+ host = host_input
181
+
182
+ port_input = questionary.text(
183
+ "Port (default: 8344):", default=str(port)
184
+ ).ask()
185
+ if port_input and port_input.isdigit():
186
+ port = int(port_input)
187
+
188
+ server_name_input = questionary.text(
189
+ "Server name (default: Flock API):", default=server_name
190
+ ).ask()
191
+ if server_name_input:
192
+ server_name = server_name_input
193
+
194
+ # Start the web server
195
+ console.print(
196
+ f"\nStarting web server on {host}:{port} {'with UI' if create_ui else 'without UI'}..."
197
+ )
198
+
199
+ # Use the Flock's start_api method
200
+ flock.start_api(
201
+ host=host, port=port, server_name=server_name, create_ui=create_ui
202
+ )
@@ -0,0 +1,443 @@
1
+ """Agent management functionality for the Flock CLI.
2
+
3
+ This module provides a CLI interface for managing agents within a Flock system,
4
+ including listing, adding, editing, and removing agents.
5
+ """
6
+
7
+ import questionary
8
+ from rich.console import Console
9
+ from rich.panel import Panel
10
+ from rich.table import Table
11
+
12
+ from flock.core.flock import Flock
13
+ from flock.core.flock_agent import FlockAgent
14
+ from flock.core.flock_factory import FlockFactory
15
+ from flock.core.util.cli_helper import init_console
16
+
17
+ # Create console instance
18
+ console = Console()
19
+
20
+
21
+ def manage_agents(flock: Flock):
22
+ """Agent management entry point.
23
+
24
+ Args:
25
+ flock: The Flock instance containing agents to manage
26
+ """
27
+ if not flock:
28
+ console.print("[bold red]Error: No Flock instance provided.[/]")
29
+ return
30
+
31
+ while True:
32
+ init_console()
33
+ console.print(Panel("[bold green]Agent Manager[/]"), justify="center")
34
+
35
+ agent_names = list(flock._agents.keys())
36
+ console.print(f"Flock contains [bold cyan]{len(agent_names)}[/] agents")
37
+
38
+ if agent_names:
39
+ console.print(f"Agents: {', '.join(agent_names)}")
40
+ else:
41
+ console.print("[yellow]No agents in this Flock yet.[/]")
42
+
43
+ console.line()
44
+
45
+ # Main menu
46
+ choice = questionary.select(
47
+ "What would you like to do?",
48
+ choices=[
49
+ questionary.Separator(line=" "),
50
+ "List All Agents",
51
+ "Add New Agent",
52
+ "Edit Agent",
53
+ "Remove Agent",
54
+ "Export Agent to YAML",
55
+ "Import Agent from YAML",
56
+ questionary.Separator(),
57
+ "Back to Main Menu",
58
+ ],
59
+ ).ask()
60
+
61
+ if choice == "List All Agents":
62
+ _list_agents(flock)
63
+ elif choice == "Add New Agent":
64
+ _add_agent(flock)
65
+ elif choice == "Edit Agent":
66
+ _edit_agent(flock)
67
+ elif choice == "Remove Agent":
68
+ _remove_agent(flock)
69
+ elif choice == "Export Agent to YAML":
70
+ _export_agent(flock)
71
+ elif choice == "Import Agent from YAML":
72
+ _import_agent(flock)
73
+ elif choice == "Back to Main Menu":
74
+ break
75
+
76
+ if choice != "Back to Main Menu":
77
+ input("\nPress Enter to continue...")
78
+
79
+
80
+ def _list_agents(flock: Flock):
81
+ """List all agents in the Flock.
82
+
83
+ Args:
84
+ flock: The Flock instance
85
+ """
86
+ agent_names = list(flock._agents.keys())
87
+
88
+ if not agent_names:
89
+ console.print("[yellow]No agents in this Flock.[/]")
90
+ return
91
+
92
+ # Create table for agents
93
+ table = Table(title="Agents in Flock")
94
+ table.add_column("Name", style="cyan")
95
+ table.add_column("Model", style="green")
96
+ table.add_column("Description", style="yellow")
97
+ table.add_column("Input", style="magenta")
98
+ table.add_column("Output", style="magenta")
99
+
100
+ for name in agent_names:
101
+ agent = flock._agents[name]
102
+
103
+ # Format model nicely
104
+ model = agent.model or flock.model or "Default"
105
+
106
+ # Format description (truncate if too long)
107
+ description = str(agent.description)
108
+ if len(description) > 30:
109
+ description = description[:27] + "..."
110
+
111
+ # Format input/output (truncate if too long)
112
+ input_str = str(agent.input)
113
+ if len(input_str) > 30:
114
+ input_str = input_str[:27] + "..."
115
+
116
+ output_str = str(agent.output)
117
+ if len(output_str) > 30:
118
+ output_str = output_str[:27] + "..."
119
+
120
+ table.add_row(
121
+ name,
122
+ model,
123
+ description,
124
+ input_str,
125
+ output_str,
126
+ )
127
+
128
+ console.print(table)
129
+
130
+ # Option to view detailed info for a specific agent
131
+ if len(agent_names) > 0:
132
+ view_details = questionary.confirm(
133
+ "View detailed information for an agent?",
134
+ default=False,
135
+ ).ask()
136
+
137
+ if view_details:
138
+ agent_to_view = questionary.select(
139
+ "Select an agent to view:",
140
+ choices=agent_names,
141
+ ).ask()
142
+
143
+ if agent_to_view:
144
+ _view_agent_details(flock._agents[agent_to_view])
145
+
146
+
147
+ def _view_agent_details(agent: FlockAgent):
148
+ """Display detailed information about an agent.
149
+
150
+ Args:
151
+ agent: The agent to display details for
152
+ """
153
+ init_console()
154
+ console.print(
155
+ Panel(f"[bold green]Agent Details: {agent.name}[/]"), justify="center"
156
+ )
157
+
158
+ # Create a panel for each section
159
+ basic_info = Table(show_header=False, box=None)
160
+ basic_info.add_column("Property", style="cyan")
161
+ basic_info.add_column("Value", style="green")
162
+
163
+ basic_info.add_row("Name", agent.name)
164
+ basic_info.add_row("Model", str(agent.model or "Default"))
165
+ basic_info.add_row("Description", str(agent.description))
166
+ basic_info.add_row("Input", str(agent.input))
167
+ basic_info.add_row("Output", str(agent.output))
168
+ basic_info.add_row("Use Cache", str(agent.use_cache))
169
+
170
+ console.print(Panel(basic_info, title="Basic Information"))
171
+
172
+ # Evaluator info
173
+ evaluator_info = (
174
+ f"Type: {type(agent.evaluator).__name__ if agent.evaluator else 'None'}"
175
+ )
176
+ console.print(Panel(evaluator_info, title="Evaluator"))
177
+
178
+ # Router info
179
+ router_info = f"Type: {type(agent.handoff_router).__name__ if agent.handoff_router else 'None'}"
180
+ console.print(Panel(router_info, title="Router"))
181
+
182
+ # Tools
183
+ if agent.tools:
184
+ tool_names = [t.__name__ for t in agent.tools]
185
+ tools_info = ", ".join(tool_names)
186
+ else:
187
+ tools_info = "None"
188
+
189
+ console.print(Panel(tools_info, title="Tools"))
190
+
191
+ # Modules
192
+ if agent.modules:
193
+ module_table = Table(show_header=True)
194
+ module_table.add_column("Name", style="cyan")
195
+ module_table.add_column("Type", style="green")
196
+ module_table.add_column("Enabled", style="yellow")
197
+
198
+ for name, module in agent.modules.items():
199
+ module_table.add_row(
200
+ name,
201
+ type(module).__name__,
202
+ "Yes" if module.config.enabled else "No",
203
+ )
204
+
205
+ console.print(Panel(module_table, title="Modules"))
206
+ else:
207
+ console.print(Panel("None", title="Modules"))
208
+
209
+
210
+ def _add_agent(flock: Flock):
211
+ """Add a new agent to the Flock.
212
+
213
+ Args:
214
+ flock: The Flock instance to add the agent to
215
+ """
216
+ console.print("\n[bold]Add New Agent[/]")
217
+ console.line()
218
+
219
+ # Get agent name
220
+ name = questionary.text(
221
+ "Enter a name for the agent:",
222
+ default="my_agent",
223
+ ).ask()
224
+
225
+ # Check for name conflicts
226
+ if name in flock._agents:
227
+ console.print(
228
+ f"[bold red]Error: An agent named '{name}' already exists.[/]"
229
+ )
230
+ return
231
+
232
+ # Get agent description
233
+ description = questionary.text(
234
+ "Enter a description for the agent (optional):",
235
+ default="",
236
+ ).ask()
237
+
238
+ # Get input specification
239
+ input_spec = questionary.text(
240
+ "Enter input specification (e.g., 'query: str | The search query'):",
241
+ default="query",
242
+ ).ask()
243
+
244
+ # Get output specification
245
+ output_spec = questionary.text(
246
+ "Enter output specification (e.g., 'result: str | The generated result'):",
247
+ default="result",
248
+ ).ask()
249
+
250
+ # Model selection
251
+ use_flock_model = questionary.confirm(
252
+ f"Use Flock's default model ({flock.model or 'None'})? Select 'n' to specify a different model.",
253
+ default=True,
254
+ ).ask()
255
+
256
+ if use_flock_model:
257
+ model = None # Use Flock's default
258
+ else:
259
+ default_models = [
260
+ "openai/gpt-4o",
261
+ "openai/gpt-3.5-turbo",
262
+ "anthropic/claude-3-opus-20240229",
263
+ "anthropic/claude-3-sonnet-20240229",
264
+ "gemini/gemini-1.5-pro",
265
+ "Other (specify)",
266
+ ]
267
+
268
+ model_choice = questionary.select(
269
+ "Select a model:",
270
+ choices=default_models,
271
+ ).ask()
272
+
273
+ if model_choice == "Other (specify)":
274
+ model = questionary.text(
275
+ "Enter the model identifier:",
276
+ default="openai/gpt-4o",
277
+ ).ask()
278
+ else:
279
+ model = model_choice
280
+
281
+ # Additional options
282
+ use_cache = questionary.confirm(
283
+ "Enable caching for this agent?",
284
+ default=True,
285
+ ).ask()
286
+
287
+ enable_rich_tables = questionary.confirm(
288
+ "Enable rich table output for this agent?",
289
+ default=True,
290
+ ).ask()
291
+
292
+ # Create the agent
293
+ agent = FlockFactory.create_default_agent(
294
+ name=name,
295
+ description=description,
296
+ model=model,
297
+ input=input_spec,
298
+ output=output_spec,
299
+ use_cache=use_cache,
300
+ enable_rich_tables=enable_rich_tables,
301
+ )
302
+
303
+ # Add the agent to the Flock
304
+ flock.add_agent(agent)
305
+ console.print(f"\n[green]✓[/] Agent '{name}' created and added to Flock!")
306
+
307
+
308
+ def _edit_agent(flock: Flock):
309
+ """Edit an existing agent in the Flock.
310
+
311
+ Args:
312
+ flock: The Flock instance containing the agent to edit
313
+ """
314
+ agent_names = list(flock._agents.keys())
315
+
316
+ if not agent_names:
317
+ console.print("[yellow]No agents in this Flock to edit.[/]")
318
+ return
319
+
320
+ # Select agent to edit
321
+ agent_name = questionary.select(
322
+ "Select an agent to edit:",
323
+ choices=agent_names,
324
+ ).ask()
325
+
326
+ if not agent_name:
327
+ return
328
+
329
+ agent = flock._agents[agent_name]
330
+
331
+ # Choose edit method
332
+ edit_choice = questionary.select(
333
+ "How would you like to edit this agent?",
334
+ choices=[
335
+ "Use Abstract Editor (Field by Field)",
336
+ "Edit YAML Directly",
337
+ "Cancel",
338
+ ],
339
+ ).ask()
340
+
341
+ if edit_choice == "Use Abstract Editor (Field by Field)":
342
+ # Not fully implemented yet
343
+ console.print(
344
+ "[yellow]Abstract editor not fully implemented. Opening YAML editor instead.[/]"
345
+ )
346
+ from flock.cli.yaml_editor import yaml_editor
347
+
348
+ updated_agent = yaml_editor(agent)
349
+ if updated_agent and isinstance(updated_agent, FlockAgent):
350
+ flock._agents[agent_name] = updated_agent
351
+
352
+ elif edit_choice == "Edit YAML Directly":
353
+ from flock.cli.yaml_editor import _edit_yaml_directly
354
+
355
+ updated_agent = _edit_yaml_directly(agent)
356
+ if updated_agent and isinstance(updated_agent, FlockAgent):
357
+ flock._agents[agent_name] = updated_agent
358
+ console.print(f"\n[green]✓[/] Agent '{agent_name}' updated!")
359
+
360
+
361
+ def _remove_agent(flock: Flock):
362
+ """Remove an agent from the Flock.
363
+
364
+ Args:
365
+ flock: The Flock instance containing the agent to remove
366
+ """
367
+ agent_names = list(flock._agents.keys())
368
+
369
+ if not agent_names:
370
+ console.print("[yellow]No agents in this Flock to remove.[/]")
371
+ return
372
+
373
+ # Select agent to remove
374
+ agent_name = questionary.select(
375
+ "Select an agent to remove:",
376
+ choices=agent_names,
377
+ ).ask()
378
+
379
+ if not agent_name:
380
+ return
381
+
382
+ # Confirm deletion
383
+ confirm = questionary.confirm(
384
+ f"Are you sure you want to remove agent '{agent_name}'?",
385
+ default=False,
386
+ ).ask()
387
+
388
+ if confirm:
389
+ del flock._agents[agent_name]
390
+ console.print(f"\n[green]✓[/] Agent '{agent_name}' removed from Flock!")
391
+
392
+
393
+ def _export_agent(flock: Flock):
394
+ """Export an agent to a YAML file.
395
+
396
+ Args:
397
+ flock: The Flock instance containing the agent to export
398
+ """
399
+ agent_names = list(flock._agents.keys())
400
+
401
+ if not agent_names:
402
+ console.print("[yellow]No agents in this Flock to export.[/]")
403
+ return
404
+
405
+ # Select agent to export
406
+ agent_name = questionary.select(
407
+ "Select an agent to export:",
408
+ choices=agent_names,
409
+ ).ask()
410
+
411
+ if not agent_name:
412
+ return
413
+
414
+ agent = flock._agents[agent_name]
415
+
416
+ # Get file path
417
+ file_path = questionary.text(
418
+ "Enter file path to save agent:",
419
+ default=f"{agent_name}.agent.yaml",
420
+ ).ask()
421
+
422
+ # Ensure the file has the correct extension
423
+ if not file_path.endswith((".yaml", ".yml")):
424
+ file_path += ".yaml"
425
+
426
+ try:
427
+ # Save the agent to YAML
428
+ agent.to_yaml_file(file_path)
429
+ console.print(
430
+ f"\n[green]✓[/] Agent '{agent_name}' exported to {file_path}"
431
+ )
432
+ except Exception as e:
433
+ console.print(f"\n[bold red]Error exporting agent:[/] {e!s}")
434
+
435
+
436
+ def _import_agent(flock: Flock):
437
+ """Import an agent from a YAML file.
438
+
439
+ Args:
440
+ flock: The Flock instance to import the agent into
441
+ """
442
+ console.print("[yellow]Import functionality not yet implemented.[/]")
443
+ # TODO: Implement agent import from YAML file
@@ -0,0 +1,29 @@
1
+ """View execution results and history.
2
+
3
+ This module provides functionality to view the results of previous Flock executions.
4
+ """
5
+
6
+ from rich.console import Console
7
+ from rich.panel import Panel
8
+
9
+ from flock.core.flock import Flock
10
+ from flock.core.util.cli_helper import init_console
11
+
12
+ # Create console instance
13
+ console = Console()
14
+
15
+
16
+ def view_results(flock: Flock):
17
+ """View execution results for a Flock instance.
18
+
19
+ Args:
20
+ flock: The Flock instance to view results for
21
+ """
22
+ init_console()
23
+ console.print(Panel("[bold green]View Results[/]"), justify="center")
24
+ console.print(
25
+ "[yellow]Results history functionality not yet implemented.[/]"
26
+ )
27
+ console.print(
28
+ "This feature will allow viewing and filtering past execution results."
29
+ )