weco 0.1.10__py3-none-any.whl → 0.2.0__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.
- weco/__init__.py +4 -4
- weco/api.py +89 -0
- weco/cli.py +333 -0
- weco/panels.py +359 -0
- weco/utils.py +114 -175
- weco-0.2.0.dist-info/METADATA +129 -0
- weco-0.2.0.dist-info/RECORD +11 -0
- {weco-0.1.10.dist-info → weco-0.2.0.dist-info}/WHEEL +1 -1
- weco-0.2.0.dist-info/entry_points.txt +2 -0
- {weco-0.1.10.dist-info → weco-0.2.0.dist-info/licenses}/LICENSE +2 -1
- weco/client.py +0 -586
- weco/constants.py +0 -4
- weco/functional.py +0 -184
- weco-0.1.10.dist-info/METADATA +0 -125
- weco-0.1.10.dist-info/RECORD +0 -10
- {weco-0.1.10.dist-info → weco-0.2.0.dist-info}/top_level.txt +0 -0
weco/__init__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
# DO NOT EDIT
|
|
2
|
+
__pkg_version__ = "0.2.0"
|
|
3
|
+
__api_version__ = "v1"
|
|
4
|
+
__base_url__ = f"https://api.aide.weco.ai/{__api_version__}"
|
weco/api.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
from typing import Dict, Any
|
|
2
|
+
import rich
|
|
3
|
+
import requests
|
|
4
|
+
from weco import __pkg_version__, __base_url__
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def handle_api_error(e: requests.exceptions.HTTPError, console: rich.console.Console) -> None:
|
|
9
|
+
"""Extract and display error messages from API responses."""
|
|
10
|
+
try:
|
|
11
|
+
error_data = e.response.json()
|
|
12
|
+
error_message = error_data.get("detail", str(e))
|
|
13
|
+
console.print(f"[bold red]Server Error:[/] {error_message}")
|
|
14
|
+
except Exception:
|
|
15
|
+
# If we can't parse the JSON, just show the original error
|
|
16
|
+
console.print(f"[bold red]Server Error:[/] {str(e)}")
|
|
17
|
+
sys.exit(1)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def start_optimization_session(
|
|
21
|
+
console: rich.console.Console,
|
|
22
|
+
source_code: str,
|
|
23
|
+
evaluation_command: str,
|
|
24
|
+
metric_name: str,
|
|
25
|
+
maximize: bool,
|
|
26
|
+
steps: int,
|
|
27
|
+
code_generator_config: Dict[str, Any],
|
|
28
|
+
evaluator_config: Dict[str, Any],
|
|
29
|
+
search_policy_config: Dict[str, Any],
|
|
30
|
+
additional_instructions: str = None,
|
|
31
|
+
api_keys: Dict[str, Any] = {},
|
|
32
|
+
) -> Dict[str, Any]:
|
|
33
|
+
"""Start the optimization session."""
|
|
34
|
+
with console.status("[bold green]Starting Optimization..."):
|
|
35
|
+
try:
|
|
36
|
+
response = requests.post(
|
|
37
|
+
f"{__base_url__}/sessions",
|
|
38
|
+
json={
|
|
39
|
+
"source_code": source_code,
|
|
40
|
+
"additional_instructions": additional_instructions,
|
|
41
|
+
"objective": {"evaluation_command": evaluation_command, "metric_name": metric_name, "maximize": maximize},
|
|
42
|
+
"optimizer": {
|
|
43
|
+
"steps": steps,
|
|
44
|
+
"code_generator": code_generator_config,
|
|
45
|
+
"evaluator": evaluator_config,
|
|
46
|
+
"search_policy": search_policy_config,
|
|
47
|
+
},
|
|
48
|
+
"metadata": {"client_name": "cli", "client_version": __pkg_version__, **api_keys},
|
|
49
|
+
},
|
|
50
|
+
)
|
|
51
|
+
response.raise_for_status()
|
|
52
|
+
return response.json()
|
|
53
|
+
except requests.exceptions.HTTPError as e:
|
|
54
|
+
handle_api_error(e=e, console=console)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def evaluate_feedback_then_suggest_next_solution(
|
|
58
|
+
console: rich.console.Console,
|
|
59
|
+
session_id: str,
|
|
60
|
+
execution_output: str,
|
|
61
|
+
additional_instructions: str = None,
|
|
62
|
+
api_keys: Dict[str, Any] = {},
|
|
63
|
+
) -> Dict[str, Any]:
|
|
64
|
+
"""Evaluate the feedback and suggest the next solution."""
|
|
65
|
+
try:
|
|
66
|
+
response = requests.post(
|
|
67
|
+
f"{__base_url__}/sessions/{session_id}/suggest",
|
|
68
|
+
json={
|
|
69
|
+
"execution_output": execution_output,
|
|
70
|
+
"additional_instructions": additional_instructions,
|
|
71
|
+
"metadata": {**api_keys},
|
|
72
|
+
},
|
|
73
|
+
)
|
|
74
|
+
response.raise_for_status()
|
|
75
|
+
return response.json()
|
|
76
|
+
except requests.exceptions.HTTPError as e:
|
|
77
|
+
handle_api_error(e=e, console=console)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def get_optimization_session_status(
|
|
81
|
+
console: rich.console.Console, session_id: str, include_history: bool = False
|
|
82
|
+
) -> Dict[str, Any]:
|
|
83
|
+
"""Get the current status of the optimization session."""
|
|
84
|
+
try:
|
|
85
|
+
response = requests.get(f"{__base_url__}/sessions/{session_id}", params={"include_history": include_history})
|
|
86
|
+
response.raise_for_status()
|
|
87
|
+
return response.json()
|
|
88
|
+
except requests.exceptions.HTTPError as e:
|
|
89
|
+
handle_api_error(e=e, console=console)
|
weco/cli.py
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import sys
|
|
3
|
+
import pathlib
|
|
4
|
+
import math
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
from rich.live import Live
|
|
7
|
+
from rich.panel import Panel
|
|
8
|
+
from rich.traceback import install
|
|
9
|
+
from .api import start_optimization_session, evaluate_feedback_then_suggest_next_solution, get_optimization_session_status
|
|
10
|
+
from .panels import (
|
|
11
|
+
SummaryPanel,
|
|
12
|
+
PlanPanel,
|
|
13
|
+
Node,
|
|
14
|
+
MetricTreePanel,
|
|
15
|
+
EvaluationOutputPanel,
|
|
16
|
+
SolutionPanels,
|
|
17
|
+
create_optimization_layout,
|
|
18
|
+
create_end_optimization_layout,
|
|
19
|
+
)
|
|
20
|
+
from .utils import (
|
|
21
|
+
read_api_keys_from_env,
|
|
22
|
+
read_additional_instructions,
|
|
23
|
+
read_from_path,
|
|
24
|
+
write_to_path,
|
|
25
|
+
run_evaluation,
|
|
26
|
+
smooth_update,
|
|
27
|
+
format_number,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
install(show_locals=True)
|
|
31
|
+
console = Console()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def main() -> None:
|
|
35
|
+
"""Main function for the Weco CLI."""
|
|
36
|
+
parser = argparse.ArgumentParser(
|
|
37
|
+
description="[bold cyan]Weco CLI[/]", formatter_class=argparse.RawDescriptionHelpFormatter
|
|
38
|
+
)
|
|
39
|
+
parser.add_argument("--source", type=str, required=True, help="Path to the Python source code (e.g. optimize.py)")
|
|
40
|
+
parser.add_argument(
|
|
41
|
+
"--eval-command", type=str, required=True, help="Command to run for evaluation (e.g. 'python eval.py --arg1=val1')"
|
|
42
|
+
)
|
|
43
|
+
parser.add_argument("--metric", type=str, required=True, help="Metric to optimize")
|
|
44
|
+
parser.add_argument("--maximize", type=bool, required=True, help="Maximize the metric")
|
|
45
|
+
parser.add_argument("--steps", type=int, required=True, help="Number of steps to run")
|
|
46
|
+
parser.add_argument("--model", type=str, required=True, help="Model to use for optimization")
|
|
47
|
+
parser.add_argument(
|
|
48
|
+
"--additional-instructions",
|
|
49
|
+
default=None,
|
|
50
|
+
type=str,
|
|
51
|
+
help="Description of additional instruction or path to a file containing additional instructions",
|
|
52
|
+
)
|
|
53
|
+
args = parser.parse_args()
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
with console.status("[bold green]Loading Modules..."):
|
|
57
|
+
# Define optimization session config
|
|
58
|
+
evaluation_command = args.eval_command
|
|
59
|
+
metric_name = args.metric
|
|
60
|
+
maximize = args.maximize
|
|
61
|
+
steps = args.steps
|
|
62
|
+
code_generator_config = {"model": args.model}
|
|
63
|
+
evaluator_config = {"model": args.model}
|
|
64
|
+
search_policy_config = {
|
|
65
|
+
"num_drafts": max(1, math.ceil(0.15 * steps)), # 15% of steps
|
|
66
|
+
"debug_prob": 0.5,
|
|
67
|
+
"max_debug_depth": max(1, math.ceil(0.1 * steps)), # 10% of steps
|
|
68
|
+
}
|
|
69
|
+
# Read additional instructions
|
|
70
|
+
additional_instructions = read_additional_instructions(additional_instructions=args.additional_instructions)
|
|
71
|
+
# Read source code
|
|
72
|
+
source_fp = pathlib.Path(args.source)
|
|
73
|
+
source_code = read_from_path(fp=source_fp, is_json=False)
|
|
74
|
+
# Read API keys
|
|
75
|
+
api_keys = read_api_keys_from_env()
|
|
76
|
+
|
|
77
|
+
# Initialize panels
|
|
78
|
+
summary_panel = SummaryPanel(total_steps=steps, model=args.model)
|
|
79
|
+
plan_panel = PlanPanel()
|
|
80
|
+
solution_panels = SolutionPanels()
|
|
81
|
+
eval_output_panel = EvaluationOutputPanel()
|
|
82
|
+
tree_panel = MetricTreePanel(maximize=maximize)
|
|
83
|
+
layout = create_optimization_layout()
|
|
84
|
+
end_optimization_layout = create_end_optimization_layout()
|
|
85
|
+
|
|
86
|
+
# Start optimization session
|
|
87
|
+
session_response = start_optimization_session(
|
|
88
|
+
console=console,
|
|
89
|
+
source_code=source_code,
|
|
90
|
+
evaluation_command=evaluation_command,
|
|
91
|
+
metric_name=metric_name,
|
|
92
|
+
maximize=maximize,
|
|
93
|
+
steps=steps,
|
|
94
|
+
code_generator_config=code_generator_config,
|
|
95
|
+
evaluator_config=evaluator_config,
|
|
96
|
+
search_policy_config=search_policy_config,
|
|
97
|
+
additional_instructions=additional_instructions,
|
|
98
|
+
api_keys=api_keys,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# Define the runs directory (.runs/<session-id>)
|
|
102
|
+
session_id = session_response["session_id"]
|
|
103
|
+
runs_dir = pathlib.Path(".runs") / session_id
|
|
104
|
+
runs_dir.mkdir(parents=True, exist_ok=True)
|
|
105
|
+
|
|
106
|
+
# Save the original code (.runs/<session-id>/original.py)
|
|
107
|
+
runs_copy_source_fp = runs_dir / "original.py"
|
|
108
|
+
write_to_path(fp=runs_copy_source_fp, content=source_code)
|
|
109
|
+
|
|
110
|
+
# Write the code string to the source file path
|
|
111
|
+
# Do this after the original code is saved
|
|
112
|
+
write_to_path(fp=source_fp, content=session_response["code"])
|
|
113
|
+
|
|
114
|
+
# Update the panels with the initial solution
|
|
115
|
+
# Add session id now that we have it
|
|
116
|
+
summary_panel.session_id = session_id
|
|
117
|
+
# Set the step of the progress bar
|
|
118
|
+
summary_panel.set_step(step=0)
|
|
119
|
+
# Update the token counts
|
|
120
|
+
summary_panel.update_token_counts(usage=session_response["usage"])
|
|
121
|
+
# Update the plan
|
|
122
|
+
plan_panel.update(plan=session_response["plan"])
|
|
123
|
+
# Build the metric tree
|
|
124
|
+
tree_panel.build_metric_tree(
|
|
125
|
+
nodes=[
|
|
126
|
+
{
|
|
127
|
+
"solution_id": session_response["solution_id"],
|
|
128
|
+
"parent_id": None,
|
|
129
|
+
"code": session_response["code"],
|
|
130
|
+
"step": 0,
|
|
131
|
+
"metric_value": None,
|
|
132
|
+
"is_buggy": False,
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
)
|
|
136
|
+
# Set the current solution as unevaluated since we haven't run the evaluation function and fed it back to the model yet
|
|
137
|
+
tree_panel.set_unevaluated_node(node_id=session_response["solution_id"])
|
|
138
|
+
# Update the solution panels with the initial solution and get the panel displays
|
|
139
|
+
solution_panels.update(
|
|
140
|
+
current_node=Node(
|
|
141
|
+
id=session_response["solution_id"], parent_id=None, code=session_response["code"], metric=None, is_buggy=False
|
|
142
|
+
),
|
|
143
|
+
best_node=None,
|
|
144
|
+
)
|
|
145
|
+
current_solution_panel, best_solution_panel = solution_panels.get_display(current_step=0)
|
|
146
|
+
# Define the refresh rate
|
|
147
|
+
refresh_rate = 4
|
|
148
|
+
with Live(layout, refresh_per_second=refresh_rate, screen=True) as live:
|
|
149
|
+
# Update the entire layout
|
|
150
|
+
smooth_update(
|
|
151
|
+
live=live,
|
|
152
|
+
layout=layout,
|
|
153
|
+
sections_to_update=[
|
|
154
|
+
("summary", summary_panel.get_display()),
|
|
155
|
+
("plan", plan_panel.get_display()),
|
|
156
|
+
("tree", tree_panel.get_display()),
|
|
157
|
+
("current_solution", current_solution_panel),
|
|
158
|
+
("best_solution", best_solution_panel),
|
|
159
|
+
("eval_output", eval_output_panel.get_display()),
|
|
160
|
+
],
|
|
161
|
+
transition_delay=0.1, # Slightly longer delay for initial display
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# Run evaluation on the initial solution
|
|
165
|
+
term_out = run_evaluation(eval_command=args.eval_command)
|
|
166
|
+
|
|
167
|
+
# Update the evaluation output panel
|
|
168
|
+
eval_output_panel.update(output=term_out)
|
|
169
|
+
smooth_update(
|
|
170
|
+
live=live,
|
|
171
|
+
layout=layout,
|
|
172
|
+
sections_to_update=[("eval_output", eval_output_panel.get_display())],
|
|
173
|
+
transition_delay=0.1,
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
for step in range(1, steps):
|
|
177
|
+
# Evaluate the current output and get the next solution
|
|
178
|
+
eval_and_next_solution_response = evaluate_feedback_then_suggest_next_solution(
|
|
179
|
+
console=console,
|
|
180
|
+
session_id=session_id,
|
|
181
|
+
execution_output=term_out,
|
|
182
|
+
additional_instructions=additional_instructions,
|
|
183
|
+
api_keys=api_keys,
|
|
184
|
+
)
|
|
185
|
+
# Save next solution (.runs/<session-id>/step_<step>.py)
|
|
186
|
+
write_to_path(fp=runs_dir / f"step_{step}.py", content=eval_and_next_solution_response["code"])
|
|
187
|
+
|
|
188
|
+
# Get the optimization session status for
|
|
189
|
+
# the best solution, its score, and the history to plot the tree
|
|
190
|
+
status_response = get_optimization_session_status(console=console, session_id=session_id, include_history=True)
|
|
191
|
+
|
|
192
|
+
# Update the step of the progress bar
|
|
193
|
+
summary_panel.set_step(step=step)
|
|
194
|
+
# Update the token counts
|
|
195
|
+
summary_panel.update_token_counts(usage=eval_and_next_solution_response["usage"])
|
|
196
|
+
# Update the plan
|
|
197
|
+
plan_panel.update(plan=eval_and_next_solution_response["plan"])
|
|
198
|
+
# Build the metric tree
|
|
199
|
+
tree_panel.build_metric_tree(nodes=status_response["history"])
|
|
200
|
+
# Set the current solution as unevaluated since we haven't run the evaluation function and fed it back to the model yet
|
|
201
|
+
tree_panel.set_unevaluated_node(node_id=eval_and_next_solution_response["solution_id"])
|
|
202
|
+
|
|
203
|
+
# Update the solution panels with the next solution and best solution (and score)
|
|
204
|
+
# Figure out if we have a best solution so far
|
|
205
|
+
if status_response["best_result"] is not None:
|
|
206
|
+
best_solution_node = Node(
|
|
207
|
+
id=status_response["best_result"]["solution_id"],
|
|
208
|
+
parent_id=status_response["best_result"]["parent_id"],
|
|
209
|
+
code=status_response["best_result"]["code"],
|
|
210
|
+
metric=status_response["best_result"]["metric_value"],
|
|
211
|
+
is_buggy=status_response["best_result"]["is_buggy"],
|
|
212
|
+
)
|
|
213
|
+
else:
|
|
214
|
+
best_solution_node = None
|
|
215
|
+
|
|
216
|
+
# Create a node for the current solution
|
|
217
|
+
current_solution_node = None
|
|
218
|
+
for node in status_response["history"]:
|
|
219
|
+
if node["solution_id"] == eval_and_next_solution_response["solution_id"]:
|
|
220
|
+
current_solution_node = Node(
|
|
221
|
+
id=node["solution_id"],
|
|
222
|
+
parent_id=node["parent_id"],
|
|
223
|
+
code=node["code"],
|
|
224
|
+
metric=node["metric_value"],
|
|
225
|
+
is_buggy=node["is_buggy"],
|
|
226
|
+
)
|
|
227
|
+
if current_solution_node is None:
|
|
228
|
+
raise ValueError("Current solution node not found in history")
|
|
229
|
+
# Update the solution panels with the current and best solution
|
|
230
|
+
solution_panels.update(current_node=current_solution_node, best_node=best_solution_node)
|
|
231
|
+
current_solution_panel, best_solution_panel = solution_panels.get_display(current_step=step)
|
|
232
|
+
|
|
233
|
+
# Clear evaluation output since we are running a evaluation on a new solution
|
|
234
|
+
eval_output_panel.clear()
|
|
235
|
+
|
|
236
|
+
# Update displays with smooth transitions
|
|
237
|
+
smooth_update(
|
|
238
|
+
live=live,
|
|
239
|
+
layout=layout,
|
|
240
|
+
sections_to_update=[
|
|
241
|
+
("summary", summary_panel.get_display()),
|
|
242
|
+
("plan", plan_panel.get_display()),
|
|
243
|
+
("tree", tree_panel.get_display()),
|
|
244
|
+
("current_solution", current_solution_panel),
|
|
245
|
+
("best_solution", best_solution_panel),
|
|
246
|
+
("eval_output", eval_output_panel.get_display()),
|
|
247
|
+
],
|
|
248
|
+
transition_delay=0.08, # Slightly longer delay for more noticeable transitions
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
# Run evaluation on the current solution
|
|
252
|
+
term_out = run_evaluation(eval_command=args.eval_command)
|
|
253
|
+
eval_output_panel.update(output=term_out)
|
|
254
|
+
|
|
255
|
+
# Update evaluation output with a smooth transition
|
|
256
|
+
smooth_update(
|
|
257
|
+
live=live,
|
|
258
|
+
layout=layout,
|
|
259
|
+
sections_to_update=[("eval_output", eval_output_panel.get_display())],
|
|
260
|
+
transition_delay=0.1, # Slightly longer delay for evaluation results
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
# Ensure we pass evaluation results for the last step's generated solution
|
|
264
|
+
eval_and_next_solution_response = evaluate_feedback_then_suggest_next_solution(
|
|
265
|
+
console=console,
|
|
266
|
+
session_id=session_id,
|
|
267
|
+
execution_output=term_out,
|
|
268
|
+
additional_instructions=additional_instructions,
|
|
269
|
+
api_keys=api_keys,
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
# Update the progress bar
|
|
273
|
+
summary_panel.set_step(step=steps)
|
|
274
|
+
# Update the token counts
|
|
275
|
+
summary_panel.update_token_counts(usage=eval_and_next_solution_response["usage"])
|
|
276
|
+
# No need to update the plan panel since we have finished the optimization
|
|
277
|
+
# Get the optimization session status for
|
|
278
|
+
# the best solution, its score, and the history to plot the tree
|
|
279
|
+
status_response = get_optimization_session_status(console=console, session_id=session_id, include_history=True)
|
|
280
|
+
# Build the metric tree
|
|
281
|
+
tree_panel.build_metric_tree(nodes=status_response["history"])
|
|
282
|
+
# No need to set any solution to unevaluated since we have finished the optimization
|
|
283
|
+
# and all solutions have been evaluated
|
|
284
|
+
# No neeed to update the current solution panel since we have finished the optimization
|
|
285
|
+
# We only need to update the best solution panel
|
|
286
|
+
# Figure out if we have a best solution so far
|
|
287
|
+
if status_response["best_result"] is not None:
|
|
288
|
+
best_solution_node = Node(
|
|
289
|
+
id=status_response["best_result"]["solution_id"],
|
|
290
|
+
parent_id=status_response["best_result"]["parent_id"],
|
|
291
|
+
code=status_response["best_result"]["code"],
|
|
292
|
+
metric=status_response["best_result"]["metric_value"],
|
|
293
|
+
is_buggy=status_response["best_result"]["is_buggy"],
|
|
294
|
+
)
|
|
295
|
+
else:
|
|
296
|
+
best_solution_node = None
|
|
297
|
+
solution_panels.update(current_node=None, best_node=best_solution_node)
|
|
298
|
+
_, best_solution_panel = solution_panels.get_display(current_step=steps)
|
|
299
|
+
|
|
300
|
+
# Update the end optimization layout
|
|
301
|
+
end_optimization_layout["summary"].update(summary_panel.get_display())
|
|
302
|
+
end_optimization_layout["tree"].update(tree_panel.get_display())
|
|
303
|
+
end_optimization_layout["best_solution"].update(best_solution_panel)
|
|
304
|
+
|
|
305
|
+
# Save optimization results
|
|
306
|
+
# If the best solution does not exist or is has not been measured at the end of the optimization
|
|
307
|
+
# save the original solution as the best solution
|
|
308
|
+
best_solution_code = best_solution_node.code
|
|
309
|
+
best_solution_score = best_solution_node.metric
|
|
310
|
+
if best_solution_code is None or best_solution_score is None:
|
|
311
|
+
best_solution_content = (
|
|
312
|
+
f"# Weco could not find a better solution\n\n{read_from_path(fp=runs_copy_source_fp, is_json=False)}"
|
|
313
|
+
)
|
|
314
|
+
else:
|
|
315
|
+
# Format score for the comment
|
|
316
|
+
best_score_str = (
|
|
317
|
+
format_number(best_solution_score)
|
|
318
|
+
if best_solution_score is not None and isinstance(best_solution_score, (int, float))
|
|
319
|
+
else "N/A"
|
|
320
|
+
)
|
|
321
|
+
best_solution_content = f"# Best solution from Weco with a score of {best_score_str}\n\n{best_solution_code}"
|
|
322
|
+
|
|
323
|
+
# Save best solution to .runs/<session-id>/best.py
|
|
324
|
+
write_to_path(fp=runs_dir / "best.py", content=best_solution_content)
|
|
325
|
+
|
|
326
|
+
# write the best solution to the source file
|
|
327
|
+
write_to_path(fp=source_fp, content=best_solution_content)
|
|
328
|
+
|
|
329
|
+
console.print(end_optimization_layout)
|
|
330
|
+
|
|
331
|
+
except Exception as e:
|
|
332
|
+
console.print(Panel(f"[bold red]Error: {str(e)}", title="[bold red]Error", border_style="red"))
|
|
333
|
+
sys.exit(1)
|