flock-core 0.3.30__py3-none-any.whl → 0.3.31__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 CHANGED
@@ -1,10 +1,11 @@
1
1
  """Flock package initialization."""
2
2
 
3
+ from rich.panel import Panel
4
+
3
5
  from flock.cli.constants import CLI_EXIT, CLI_NOTES, CLI_THEME_BUILDER
4
6
  from flock.cli.load_release_notes import load_release_notes
5
- from flock.core.logging.formatters.theme_builder import theme_builder
6
7
  from flock.cli.settings import settings_editor
7
- from rich.panel import Panel
8
+ from flock.core.logging.formatters.theme_builder import theme_builder
8
9
 
9
10
 
10
11
  def main():
@@ -19,7 +20,6 @@ def main():
19
20
  CLI_LOAD_EXAMPLE,
20
21
  CLI_LOAD_FLOCK,
21
22
  CLI_SETTINGS,
22
- CLI_START_ADVANCED_MODE,
23
23
  CLI_START_WEB_SERVER,
24
24
  )
25
25
  from flock.cli.load_flock import load_flock
@@ -29,8 +29,10 @@ def main():
29
29
  while True:
30
30
  init_console()
31
31
 
32
- #console.print("Flock Management Console\n", style="bold green")
33
- console.print(Panel("[bold green]Flock Management Console[/]"), justify="center")
32
+ # console.print("Flock Management Console\n", style="bold green")
33
+ console.print(
34
+ Panel("[bold green]Flock Management Console[/]"), justify="center"
35
+ )
34
36
  console.line()
35
37
 
36
38
  result = questionary.select(
@@ -38,7 +40,7 @@ def main():
38
40
  choices=[
39
41
  questionary.Separator(line=" "),
40
42
  # CLI_CREATE_AGENT,
41
- # CLI_CREATE_FLOCK,
43
+ CLI_CREATE_FLOCK,
42
44
  # CLI_LOAD_AGENT,
43
45
  CLI_LOAD_FLOCK,
44
46
  # CLI_LOAD_EXAMPLE,
@@ -46,7 +48,6 @@ def main():
46
48
  CLI_THEME_BUILDER,
47
49
  CLI_SETTINGS,
48
50
  questionary.Separator(),
49
- CLI_START_ADVANCED_MODE,
50
51
  CLI_START_WEB_SERVER,
51
52
  questionary.Separator(),
52
53
  CLI_NOTES,
@@ -56,13 +57,24 @@ def main():
56
57
 
57
58
  if result == CLI_LOAD_FLOCK:
58
59
  load_flock()
59
- if result == CLI_THEME_BUILDER:
60
+ elif result == CLI_CREATE_FLOCK:
61
+ # This will be implemented in a separate create_flock.py
62
+ from flock.cli.create_flock import create_flock
63
+
64
+ create_flock()
65
+ elif result == CLI_THEME_BUILDER:
60
66
  theme_builder()
61
- if result == CLI_SETTINGS:
67
+ elif result == CLI_SETTINGS:
62
68
  settings_editor()
63
- if result == CLI_NOTES:
69
+ elif result == CLI_START_WEB_SERVER:
70
+ # Simple web server without a loaded Flock - could create a new one
71
+ console.print(
72
+ "[yellow]Web server without loaded Flock not yet implemented.[/]"
73
+ )
74
+ input("\nPress Enter to continue...")
75
+ elif result == CLI_NOTES:
64
76
  load_release_notes()
65
- if result == CLI_EXIT:
77
+ elif result == CLI_EXIT:
66
78
  break
67
79
  input("\nPress Enter to continue...\n\n")
68
80
 
flock/cli/constants.py CHANGED
@@ -1,15 +1,14 @@
1
1
  """Constants for the CLI module."""
2
2
 
3
3
  CLI_CREATE_AGENT = "Create an agent"
4
- CLI_CREATE_FLOCK = "Create a flock"
4
+ CLI_CREATE_FLOCK = "Create a new Flock"
5
5
  CLI_LOAD_AGENT = "Load an agent"
6
6
  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
10
  CLI_NOTES = "'Hummingbird' release notes"
11
- CLI_START_ADVANCED_MODE = "Start advanced mode (coming soon)"
12
- CLI_START_WEB_SERVER = "Start web server (coming soon)"
11
+ CLI_START_WEB_SERVER = "Start web server"
13
12
  CLI_EXIT = "Exit"
14
13
  CLI_CHOICES = [
15
14
  CLI_CREATE_AGENT,
@@ -18,7 +17,6 @@ CLI_CHOICES = [
18
17
  CLI_LOAD_FLOCK,
19
18
  CLI_LOAD_EXAMPLE,
20
19
  CLI_SETTINGS,
21
- CLI_START_ADVANCED_MODE,
22
20
  CLI_START_WEB_SERVER,
23
21
  CLI_EXIT,
24
22
  ]
flock/cli/create_flock.py CHANGED
@@ -1 +1,220 @@
1
- # TODO
1
+ """Create a new Flock through a guided wizard.
2
+
3
+ This module provides a wizard-like interface for creating new Flock instances,
4
+ with options for basic configuration and initial agent creation.
5
+ """
6
+
7
+ from pathlib import Path
8
+
9
+ import questionary
10
+ from rich.console import Console
11
+ from rich.panel import Panel
12
+
13
+ from flock.cli.loaded_flock_cli import start_loaded_flock_cli
14
+ from flock.core.flock import Flock
15
+ from flock.core.flock_factory import FlockFactory
16
+ from flock.core.util.cli_helper import init_console
17
+
18
+ # Create console instance
19
+ console = Console()
20
+
21
+
22
+ def create_flock():
23
+ """Create a new Flock through a guided wizard."""
24
+ init_console()
25
+ console.print(Panel("[bold green]Create New Flock[/]"), justify="center")
26
+ console.line()
27
+
28
+ # Step 1: Basic Flock Configuration
29
+ console.print("[bold]Step 1: Basic Flock Configuration[/]")
30
+ console.line()
31
+
32
+ # Get description
33
+ description = questionary.text(
34
+ "Enter a description for this Flock (optional):",
35
+ default="",
36
+ ).ask()
37
+
38
+ # Default model selection
39
+ default_models = [
40
+ "openai/gpt-4o",
41
+ "openai/gpt-3.5-turbo",
42
+ "anthropic/claude-3-opus-20240229",
43
+ "anthropic/claude-3-sonnet-20240229",
44
+ "gemini/gemini-1.5-pro",
45
+ "Other (specify)",
46
+ ]
47
+
48
+ model_choice = questionary.select(
49
+ "Select a default model:",
50
+ choices=default_models,
51
+ ).ask()
52
+
53
+ if model_choice == "Other (specify)":
54
+ model = questionary.text(
55
+ "Enter the model identifier:",
56
+ default="openai/gpt-4o",
57
+ ).ask()
58
+ else:
59
+ model = model_choice
60
+
61
+ # Execution options
62
+ enable_temporal = questionary.confirm(
63
+ "Enable Temporal for distributed execution?",
64
+ default=False,
65
+ ).ask()
66
+
67
+ # Logging configuration
68
+ enable_logging = questionary.confirm(
69
+ "Enable logging?",
70
+ default=True,
71
+ ).ask()
72
+
73
+ # Create the Flock instance
74
+ flock = Flock(
75
+ model=model,
76
+ description=description,
77
+ enable_temporal=enable_temporal,
78
+ enable_logging=enable_logging,
79
+ )
80
+
81
+ console.print("\n[green]✓[/] Flock created successfully!")
82
+ console.line()
83
+
84
+ # Step 2: Create Initial Agent (optional)
85
+ create_agent = questionary.confirm(
86
+ "Would you like to create an initial agent?",
87
+ default=True,
88
+ ).ask()
89
+
90
+ if create_agent:
91
+ _create_initial_agent(flock)
92
+
93
+ # Step 3: Save Options
94
+ console.print("\n[bold]Step 3: Save Options[/]")
95
+ console.line()
96
+
97
+ save_choice = questionary.select(
98
+ "What would you like to do with this Flock?",
99
+ choices=[
100
+ "Save to YAML file",
101
+ "Continue in CLI without saving",
102
+ "Execute immediately",
103
+ "Cancel and discard",
104
+ ],
105
+ ).ask()
106
+
107
+ if save_choice == "Save to YAML file":
108
+ _save_flock_to_yaml(flock)
109
+
110
+ # Ask if user wants to continue working with this Flock
111
+ continue_with_flock = questionary.confirm(
112
+ "Would you like to continue working with this Flock in the CLI?",
113
+ default=True,
114
+ ).ask()
115
+
116
+ if continue_with_flock:
117
+ start_loaded_flock_cli(flock, server_name="New Flock")
118
+
119
+ elif save_choice == "Continue in CLI without saving":
120
+ start_loaded_flock_cli(flock, server_name="New Flock")
121
+
122
+ elif save_choice == "Execute immediately":
123
+ from flock.cli.execute_flock import execute_flock
124
+
125
+ try:
126
+ execute_flock(flock)
127
+ except ImportError:
128
+ console.print(
129
+ "[yellow]Execute functionality not yet implemented.[/]"
130
+ )
131
+ input("\nPress Enter to continue...")
132
+ start_loaded_flock_cli(flock, server_name="New Flock")
133
+
134
+
135
+ def _create_initial_agent(flock):
136
+ """Create an initial agent for the Flock.
137
+
138
+ Args:
139
+ flock: The Flock instance to add the agent to
140
+ """
141
+ console.print("\n[bold]Step 2: Create Initial Agent[/]")
142
+ console.line()
143
+
144
+ # Get agent name
145
+ name = questionary.text(
146
+ "Enter a name for the agent:",
147
+ default="my_agent",
148
+ ).ask()
149
+
150
+ # Get agent description
151
+ description = questionary.text(
152
+ "Enter a description for the agent (optional):",
153
+ default="",
154
+ ).ask()
155
+
156
+ # Get input specification
157
+ input_spec = questionary.text(
158
+ "Enter input specification (e.g., 'query: str | The search query'):",
159
+ default="query",
160
+ ).ask()
161
+
162
+ # Get output specification
163
+ output_spec = questionary.text(
164
+ "Enter output specification (e.g., 'result: str | The generated result'):",
165
+ default="result",
166
+ ).ask()
167
+
168
+ # Additional options
169
+ use_cache = questionary.confirm(
170
+ "Enable caching for this agent?",
171
+ default=True,
172
+ ).ask()
173
+
174
+ enable_rich_tables = questionary.confirm(
175
+ "Enable rich table output for this agent?",
176
+ default=True,
177
+ ).ask()
178
+
179
+ # Create the agent
180
+ agent = FlockFactory.create_default_agent(
181
+ name=name,
182
+ description=description,
183
+ input=input_spec,
184
+ output=output_spec,
185
+ use_cache=use_cache,
186
+ enable_rich_tables=enable_rich_tables,
187
+ )
188
+
189
+ # Add the agent to the Flock
190
+ flock.add_agent(agent)
191
+ console.print(f"\n[green]✓[/] Agent '{name}' created and added to Flock!")
192
+
193
+
194
+ def _save_flock_to_yaml(flock):
195
+ """Save the Flock to a YAML file.
196
+
197
+ Args:
198
+ flock: The Flock instance to save
199
+ """
200
+ # Get file path
201
+ default_name = "my_flock.flock.yaml"
202
+ file_path = questionary.text(
203
+ "Enter file path to save Flock:",
204
+ default=default_name,
205
+ ).ask()
206
+
207
+ # Ensure the file has the correct extension
208
+ if not file_path.endswith((".yaml", ".yml")):
209
+ file_path += ".yaml"
210
+
211
+ # Create directory if it doesn't exist
212
+ save_path = Path(file_path)
213
+ save_path.parent.mkdir(parents=True, exist_ok=True)
214
+
215
+ try:
216
+ # Save the Flock to YAML
217
+ flock.to_yaml_file(file_path)
218
+ console.print(f"\n[green]✓[/] Flock saved to {file_path}")
219
+ except Exception as e:
220
+ console.print(f"\n[bold red]Error saving Flock:[/] {e!s}")
@@ -0,0 +1,200 @@
1
+ """Execute a Flock instance with a selected agent.
2
+
3
+ This module provides functionality to execute a Flock instance with
4
+ a selected agent and input configuration.
5
+ """
6
+
7
+ import json
8
+
9
+ import questionary
10
+ from rich.console import Console
11
+ from rich.panel import Panel
12
+
13
+ from flock.core.flock import Flock
14
+ from flock.core.util.cli_helper import init_console
15
+
16
+ # Create console instance
17
+ console = Console()
18
+
19
+
20
+ def execute_flock(flock: Flock):
21
+ """Execute a Flock instance.
22
+
23
+ Args:
24
+ flock: The Flock instance to execute
25
+ """
26
+ if not flock:
27
+ console.print("[bold red]Error: No Flock instance provided.[/]")
28
+ return
29
+
30
+ agent_names = list(flock._agents.keys())
31
+
32
+ if not agent_names:
33
+ console.print("[yellow]No agents in this Flock to execute.[/]")
34
+ return
35
+
36
+ init_console()
37
+ console.print(Panel("[bold green]Execute Flock[/]"), justify="center")
38
+
39
+ # Step 1: Select start agent
40
+ console.print("\n[bold]Step 1: Select Start Agent[/]")
41
+
42
+ start_agent_name = questionary.select(
43
+ "Select an agent to start with:",
44
+ choices=agent_names,
45
+ ).ask()
46
+
47
+ if not start_agent_name:
48
+ return
49
+
50
+ start_agent = flock._agents[start_agent_name]
51
+
52
+ # Step 2: Configure input
53
+ console.print("\n[bold]Step 2: Configure Input[/]")
54
+
55
+ # Parse input schema
56
+ input_fields = _parse_input_schema(start_agent.input)
57
+
58
+ # If we couldn't parse any fields, ask for generic input
59
+ if not input_fields:
60
+ raw_input = questionary.text(
61
+ "Enter input (JSON format):",
62
+ default="{}",
63
+ ).ask()
64
+
65
+ try:
66
+ input_data = json.loads(raw_input)
67
+ except json.JSONDecodeError:
68
+ console.print("[bold red]Error: Invalid JSON input.[/]")
69
+ return
70
+ else:
71
+ # Otherwise, ask for each field
72
+ input_data = {}
73
+
74
+ for field, info in input_fields.items():
75
+ field_type = info.get("type", "str")
76
+ description = info.get("description", "")
77
+ prompt = f"Enter value for '{field}'"
78
+
79
+ if description:
80
+ prompt += f" ({description})"
81
+
82
+ prompt += ":"
83
+
84
+ value = questionary.text(prompt).ask()
85
+
86
+ # Convert value to appropriate type
87
+ if field_type == "int":
88
+ try:
89
+ value = int(value)
90
+ except ValueError:
91
+ console.print(
92
+ f"[yellow]Warning: Could not convert value to int, using as string.[/]"
93
+ )
94
+
95
+ input_data[field] = value
96
+
97
+ # Step 3: Run Options
98
+ console.print("\n[bold]Step 3: Run Options[/]")
99
+
100
+ # Logging options
101
+ enable_logging = questionary.confirm(
102
+ "Enable detailed logging?",
103
+ default=False,
104
+ ).ask()
105
+
106
+ # Preview input
107
+ console.print("\n[bold]Input Preview:[/]")
108
+ console.print(json.dumps(input_data, indent=2))
109
+
110
+ # Confirm execution
111
+ confirm = questionary.confirm(
112
+ "Execute Flock with this configuration?",
113
+ default=True,
114
+ ).ask()
115
+
116
+ if not confirm:
117
+ return
118
+
119
+ # Execute the Flock
120
+ console.print("\n[bold]Executing Flock...[/]")
121
+
122
+ try:
123
+ # Handle logging settings
124
+ if enable_logging:
125
+ # Enable logging through the logging configuration method
126
+ flock._configure_logging(True)
127
+
128
+ # Run the Flock
129
+ result = flock.run(
130
+ start_agent=start_agent_name,
131
+ input=input_data,
132
+ )
133
+
134
+ # Display result
135
+ console.print("\n[bold green]Execution Complete![/]")
136
+
137
+ if result and enable_logging:
138
+ console.print("\n[bold]Result:[/]")
139
+ if isinstance(result, dict):
140
+ # Display as formatted JSON
141
+ console.print(json.dumps(result, indent=2))
142
+ else:
143
+ # Display as plain text
144
+ console.print(str(result))
145
+
146
+ except Exception as e:
147
+ console.print(f"\n[bold red]Error during execution:[/] {e!s}")
148
+
149
+
150
+ def _parse_input_schema(input_schema: str) -> dict[str, dict[str, str]]:
151
+ """Parse the input schema string into a field dictionary.
152
+
153
+ Args:
154
+ input_schema: The input schema string (e.g., "query: str | The search query")
155
+
156
+ Returns:
157
+ A dictionary mapping field names to field info (type, description)
158
+ """
159
+ if not input_schema:
160
+ return {}
161
+
162
+ fields = {}
163
+
164
+ try:
165
+ # Split by comma for multiple fields
166
+ for field_def in input_schema.split(","):
167
+ field_def = field_def.strip()
168
+
169
+ # Check for type hint with colon
170
+ if ":" in field_def:
171
+ field_name, rest = field_def.split(":", 1)
172
+ field_name = field_name.strip()
173
+ rest = rest.strip()
174
+
175
+ # Check for description with pipe
176
+ if "|" in rest:
177
+ field_type, description = rest.split("|", 1)
178
+ fields[field_name] = {
179
+ "type": field_type.strip(),
180
+ "description": description.strip(),
181
+ }
182
+ else:
183
+ fields[field_name] = {"type": rest.strip()}
184
+ else:
185
+ # Just a field name without type hint
186
+ if "|" in field_def:
187
+ field_name, description = field_def.split("|", 1)
188
+ fields[field_name.strip()] = {
189
+ "description": description.strip()
190
+ }
191
+ else:
192
+ fields[field_def.strip()] = {}
193
+
194
+ except Exception as e:
195
+ console.print(
196
+ f"[yellow]Warning: Could not parse input schema: {e!s}[/]"
197
+ )
198
+ return {}
199
+
200
+ return fields
flock/cli/load_flock.py CHANGED
@@ -6,6 +6,7 @@ import questionary
6
6
  from rich.console import Console
7
7
  from rich.markdown import Markdown
8
8
 
9
+ from flock.cli.loaded_flock_cli import start_loaded_flock_cli
9
10
  from flock.core.flock import Flock
10
11
 
11
12
 
@@ -14,25 +15,44 @@ def filter(file_path) -> bool:
14
15
  path = Path(file_path)
15
16
  if path.is_dir():
16
17
  return True
17
- return path.is_file() and path.suffix == ".flock"
18
+ return path.is_file() and (
19
+ path.suffix == ".flock"
20
+ or path.suffix == ".yaml"
21
+ or path.suffix == ".yml"
22
+ )
18
23
 
19
24
 
20
25
  def load_flock():
21
26
  """Load a Flock from a file."""
22
27
  console = Console()
23
28
 
24
- console.print("\nPlease select a *.flock file\n", style="bold green")
29
+ console.print(
30
+ "\nPlease select a *.flock, *.yaml, or *.yml file\n", style="bold green"
31
+ )
25
32
 
26
33
  result = questionary.path("", file_filter=filter).ask()
27
34
 
35
+ if not result:
36
+ return
37
+
28
38
  selected_file = Path(result)
29
39
  if selected_file.is_file():
30
40
  console.print(f"Selected file: {selected_file}", style="bold green")
31
41
 
32
- flock = Flock.load_from_file(result)
42
+ try:
43
+ flock = Flock.load_from_file(result)
44
+
45
+ console.line()
46
+ console.print(
47
+ Markdown("# Flock loaded successfully"), style="bold green"
48
+ )
49
+ console.line()
33
50
 
34
- console.line()
35
- console.print(Markdown("# Flock loaded...."), style="bold orange")
36
- console.line()
51
+ # Instead of just running the Flock, start our enhanced CLI
52
+ start_loaded_flock_cli(
53
+ flock, server_name=f"Flock - {selected_file.name}"
54
+ )
37
55
 
38
- flock.run()
56
+ except Exception as e:
57
+ console.print(f"Error loading Flock: {e!s}", style="bold red")
58
+ input("\nPress Enter to continue...")