Skip to content

Commit 3886bd5

Browse files
committed
nit: clean up results parser logic
Signed-off-by: vsoch <[email protected]>
1 parent 3860d1a commit 3886bd5

File tree

4 files changed

+39
-38
lines changed

4 files changed

+39
-38
lines changed

fractale/agent/kubernetes/job/agent.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,9 @@ def finish_deploy(self, context, obj, deploy_dir):
254254

255255
# If the pod was OOMKIlled, this shouldn't cycle around as failure during optimization
256256
if reason == "OOMKilled" and context.get("is_optimizing"):
257-
return self.optimize(context, obj, context.result, "The last attempt was OOMKilled.")
257+
return self.optimize(
258+
context, obj, context.result, "The last attempt was OOMKilled."
259+
)
258260

259261
diagnostics = self.get_diagnostics(obj, pod)
260262
obj.delete()

fractale/agent/kubernetes/minicluster/agent.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,21 @@ def check_flux_view(self, minicluster):
3838
"""
3939
If a view is defined, ensure it is in allowed set.
4040
"""
41-
if not minicluster:
42-
return minicluster
4341
view = minicluster.get("spec", {}).get("flux", {}).get("container", {}).get("image")
4442
if not view:
45-
return minicluster
43+
return yaml.dump(minicluster)
44+
45+
# If the agent gets it wrong it needs to know what are valid options
46+
comment = ""
4647
if view not in flux_views:
47-
logger.warning(f"Flux view {view} is not valid and will not be used.")
48+
comment = f"Flux view {view} is not valid and will not be used."
49+
logger.warning(comment)
50+
comment = "# " + comment + "\n# Choices include: " + ", ".join(flux_views) + "\n"
4851
del minicluster["spec"]["flux"]["container"]
4952
if not minicluster["spec"]["flux"]:
5053
del minicluster["spec"]["flux"]
51-
return minicluster
54+
55+
return yaml.dump(minicluster) + "\n" + comment
5256

5357
@timed
5458
def deploy(self, context):
@@ -71,9 +75,6 @@ def deploy(self, context):
7175
if not name:
7276
return 1, "Generated YAML is missing required '.metadata.name' field."
7377

74-
# This is a common error the LLM makes
75-
minicluster = self.check_flux_view(minicluster)
76-
7778
# If it doesn't follow instructions...
7879
containers = self.get_containers(minicluster)
7980
if not containers:
@@ -92,7 +93,8 @@ def deploy(self, context):
9293
deploy_dir = tempfile.mkdtemp()
9394
print(f"[dim]Created temporary deploy context: {deploy_dir}[/dim]")
9495

95-
context.result = yaml.dump(minicluster)
96+
# Write the final minicluster after checking the view
97+
context.result = self.check_flux_view(minicluster)
9698
mc = objects.MiniCluster(name, namespace)
9799
logger.info(
98100
f"Attempt {self.attempts} to deploy Kubernetes {mc.kind}: [bold cyan]{mc.namespace}/{mc.name}"

fractale/agent/kubernetes/minicluster/prompts.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,12 @@
88
# This should explicitly state what the agent is capable of doing.
99
requires = prompts.common_requires + [
1010
"You MUST NOT create or require abstractions beyond the MiniCluster (no ConfigMap or Volume or other types)",
11-
"You MUST set spec.logging.strict to true",
11+
"You MUST set spec.logging.strict to true. You MUST NOT use mpirun or mpiexec. Flux bootstraps MPI.",
1212
"You are only scoped to edit the MiniCluster manifest for Kubernetes.",
13-
"If a library is missing or change needed to the container, use a containers[0].commands.pre block to ad it",
13+
"If a library is missing or change needed to the container, use a containers[0].commands.pre block to add it",
1414
"DO NOT CREATE A KUBERNETES JOB. You are creating a Flux MiniCluster deployed by the Flux Operator.",
1515
"You MUST set cleanup to false and you MUST set launcher to false. launcher MUST NOT be true under ANY CIRCUMSTANCES.",
1616
"You MUST NOT put a flux run or flux submit in the command. It is added by the Flux Operator."
17-
"You MUST use version v1alpha2 of the flux-framework.org minicluster.",
1817
"You MUST NOT add any sidecars. The list of containers should only have one entry.",
1918
"The command is a string and not an array. Do not edit the flux view container image.",
2019
]

fractale/agent/results/agent.py

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -97,52 +97,50 @@ def run(self, requires, log):
9797

9898
# If too many retries, ask for human input - we've hit some rare edge case.
9999
retries = 0
100-
advice = 0
101100
with_history = True
102101
attempts = []
103102

104103
# Keep trying until we at least get a match
105104
match = None
106105
while not match:
107106
regex = self.ask_gemini(prompt, with_history=with_history)
107+
108+
# The last appended will be the final (correct)
109+
attempts.append(regex)
108110
print("Received result parser from Gemini...")
109111
logger.custom(regex, title="[green]Result Parser[/green]", border_style="green")
110112
match = self.find_match(regex, log)
111113
self.metadata["assets"]["tries"] += 1
112114

115+
# If we have a match, check and cut out earlier
116+
if match:
117+
118+
# If we get a match, ask the user to verify
119+
result = match[0]
120+
if len(match) > 1:
121+
result = " ".join(match)
122+
123+
# yes / no / feedback
124+
is_correct = confirm_correct(log, result)
125+
if is_correct is True:
126+
self.metadata["assets"]["regex-attempts"] = attempts
127+
return regex
128+
elif is_correct is None:
129+
prompt += "\n" + input("Please enter feedback for the LLM:\n")
130+
else:
131+
prompt += f"\nHere is a previous attempt that produced a match but was incorrect content: {regex}"
132+
113133
# Ensure it doesn't make the same mistake...
114-
if not match:
115-
prompt += f"\nHere is a previous unsuccessful attempt: {regex}"
116-
continue
117-
118-
# If we get a match, ask the user to verify
119-
result = match[0]
120-
if len(match) > 1:
121-
result = " ".join(match)
122-
is_correct = confirm_correct(log, result)
123-
if is_correct is True:
124-
return regex
125-
126-
# Feedback case
127-
elif is_correct is None:
128-
prompt += "\n" + input("Please enter feedback for the LLM:\n")
129134
else:
130-
prompt += f"\nHere is a previous unsuccessful attempt: {regex}"
131-
attempts.append(regex)
132-
133-
# If more than 5 retries, ask for human help
134-
# Unlike retries, this counter resets
135-
if advice >= 3:
136-
prompt += "\n" + input("The agent is having trouble. Please provide advice:\n")
137-
advice += 1
135+
prompt += f"\nHere is a previous unsuccessful attempt that did not match anything: {regex}"
138136

139137
# Usually this indicates a problem.
140138
if retries >= 5:
141139
prompt = prompts.parsing_prompt % (requires, log)
142140
with_history = False
141+
retries = 0
143142

144143
retries += 1
145-
advice += 1
146144

147145
# If it's not correct, we need to try again
148146
match = None

0 commit comments

Comments
 (0)