NanduKondreddy commited on
Commit
61cc465
·
1 Parent(s): d255d10

Revert: environment.step() is now grading-only (LLM solving happens in inference.py)

Browse files
Files changed (1) hide show
  1. server/config_debug_environment.py +14 -167
server/config_debug_environment.py CHANGED
@@ -2,158 +2,28 @@
2
 
3
  Inherits from openenv.core.env_server.Environment and implements
4
  the standard reset/step/state interface with multi-task logic.
 
 
 
5
  """
6
- import asyncio
7
- import os
8
- import textwrap
9
  from typing import Optional, Any
10
  from uuid import uuid4
11
 
12
- from openai import OpenAI
13
  from openenv.core.env_server import Environment
14
  from server.models import ConfigDebugAction, ConfigDebugObservation, ConfigDebugState
15
  from server.tasks.task_registry import get_task, TASK_ORDER
16
 
17
  MAX_STEPS_PER_TASK = 5
18
 
19
- # LLM Configuration (same as inference.py)
20
- SYSTEM_PROMPT = textwrap.dedent(
21
- """
22
- You are an expert DevOps/Infrastructure engineer specializing in configuration file debugging.
23
-
24
- Your task: Fix ALL bugs in the provided configuration file.
25
-
26
- CRITICAL RULES:
27
- 1. Analyze the error message carefully - it identifies the exact problems
28
- 2. Fix EVERY bug mentioned in "Number of bugs to find"
29
- 3. Preserve exact formatting and indentation from the original (except fixes)
30
- 4. Validate syntax BEFORE returning - no invalid XML/JSON/YAML
31
- 5. Return ONLY the fixed configuration file content - absolutely no explanations or comments
32
- 6. Keep identical all lines that have no bugs
33
- 7. If there are multiple bugs, fix them ALL in one response
34
-
35
- SUCCESS CRITERIA: Your output must pass syntax validation and fix all identified bugs.
36
- """
37
- ).strip()
38
-
39
- TEMPERATURE = 0.0
40
- MAX_TOKENS = 4000
41
-
42
-
43
- def strip_code_blocks(text: str) -> str:
44
- """Remove markdown code blocks if LLM wraps output in them."""
45
- text = text.strip()
46
- if text.startswith("```"):
47
- lines = text.split("\n")
48
- if lines[-1].strip() == "```":
49
- lines = lines[1:-1]
50
- else:
51
- lines = lines[1:]
52
- text = "\n".join(lines)
53
- return text
54
-
55
-
56
- async def generate_fix_async(observation: ConfigDebugObservation, step: int = 1) -> str:
57
- """
58
- Call LLM agent to generate a fix for the current task.
59
- Returns the fixed configuration string.
60
- """
61
- # Read API credentials - try multiple env var names for compatibility
62
- api_key = os.getenv("API_KEY") or os.getenv("HF_TOKEN")
63
- api_base_url = os.getenv("API_BASE_URL")
64
-
65
- if not api_key:
66
- print(f"[LLM AGENT] Missing API_KEY or HF_TOKEN", flush=True)
67
- return ""
68
-
69
- if not api_base_url:
70
- print(f"[LLM AGENT] Missing API_BASE_URL", flush=True)
71
- return ""
72
-
73
- # Get model name
74
- model_name = os.getenv("MODEL_NAME", "gpt-4o")
75
-
76
- # Create client
77
- client = OpenAI(base_url=api_base_url, api_key=api_key)
78
-
79
- # Build prompt
80
- user_prompt = textwrap.dedent(
81
- f"""
82
- FILE TYPE: {observation.file_type.upper()}
83
- TASK: {observation.task_description}
84
- DIFFICULTY: {observation.difficulty}
85
- TOTAL BUGS TO FIX: {observation.num_bugs}
86
- BUGS FIXED SO FAR: {observation.bugs_found_so_far} of {observation.num_bugs}
87
- CURRENT ERROR: {observation.error_message}
88
- STEP: {step}
89
-
90
- THE BROKEN CONFIGURATION:
91
- {observation.broken_config}
92
-
93
- INSTRUCTIONS:
94
- 1. Review the error message above - it tells you exactly what is broken
95
- 2. You have found {observation.bugs_found_so_far} bugs so far, you need to find {observation.num_bugs} - {observation.bugs_found_so_far} more
96
- 3. Fix ALL remaining bugs in a single response
97
- 4. Keep the exact same format/indentation as the original except for the fixes
98
- 5. Output ONLY the corrected configuration file - no markdown, no explanation, no "```"
99
- 6. The fixed configuration MUST be syntactically valid {observation.file_type.upper()}
100
- """
101
- ).strip()
102
-
103
- try:
104
- print(f"[LLM AGENT] Calling model={model_name} for task={observation.task_id} step={step}", flush=True)
105
-
106
- completion = client.chat.completions.create(
107
- model=model_name,
108
- messages=[
109
- {"role": "system", "content": SYSTEM_PROMPT},
110
- {"role": "user", "content": user_prompt},
111
- ],
112
- temperature=TEMPERATURE,
113
- max_tokens=MAX_TOKENS,
114
- stream=False,
115
- )
116
-
117
- fixed_config = (completion.choices[0].message.content or "").strip()
118
-
119
- # Clean up code blocks
120
- fixed_config = strip_code_blocks(fixed_config)
121
-
122
- # Remove explanatory prefixes
123
- if fixed_config.startswith("Here") or fixed_config.startswith("Here's"):
124
- lines = fixed_config.split("\n")
125
- for i, line in enumerate(lines):
126
- if not line.startswith("Here"):
127
- fixed_config = "\n".join(lines[i:])
128
- break
129
-
130
- print(f"[LLM AGENT] Generated fix: {len(fixed_config)} chars, task={observation.task_id}", flush=True)
131
- return fixed_config
132
-
133
- except Exception as e:
134
- print(f"[LLM AGENT] Error: {e}", flush=True)
135
- return ""
136
-
137
-
138
- def generate_fix(observation: ConfigDebugObservation, step: int = 1) -> str:
139
- """
140
- Synchronous wrapper to generate fix using async LLM call.
141
- """
142
- try:
143
- return asyncio.run(generate_fix_async(observation, step))
144
- except RuntimeError as e:
145
- # If event loop already exists, use get_event_loop
146
- if "asyncio.run() cannot be called from a running event loop" in str(e):
147
- loop = asyncio.get_event_loop()
148
- return loop.run_until_complete(generate_fix_async(observation, step))
149
- raise
150
-
151
 
152
  class ConfigDebugEnvironment(Environment):
153
  """Multi-task config debugging environment.
154
 
155
- Manages 7 sequential tasks internally. Each WebSocket session
156
  (via create_fastapi_app) gets its own instance with independent state.
 
 
 
157
  """
158
 
159
  SUPPORTS_CONCURRENT_SESSIONS = True
@@ -185,37 +55,15 @@ class ConfigDebugEnvironment(Environment):
185
  return self._build_observation()
186
 
187
  def step(self, action: ConfigDebugAction, timeout_s: Optional[float] = None, **kwargs: Any) -> ConfigDebugObservation:
188
- """Process an action: run the grader, advance tasks if done."""
189
  if self._done:
190
  return self._build_observation()
191
 
192
  task_id = self._current_task_id()
193
  task = get_task(task_id)
194
 
195
- # Check if validator sent empty fixed_config (signal to autonomously solve)
196
- fc = action.fixed_config
197
- is_empty_submission = not fc or fc.strip() == ""
198
-
199
- print(f"\n[STEP] task={task_id} step={self.current_step + 1} fixed_config_empty={is_empty_submission}", flush=True)
200
-
201
- if is_empty_submission:
202
- # Validator sent empty config - environment must autonomously generate fix
203
- print(f"[AUTONOMOUS SOLVING] Generating fix for task={task_id}", flush=True)
204
- obs = self._build_observation()
205
- fixed_config = generate_fix(obs, step=self.current_step + 1)
206
-
207
- if not fixed_config:
208
- print(f"[AUTONOMOUS SOLVING] ERROR: LLM returned empty fix for task={task_id}", flush=True)
209
- fixed_config = "" # Fallback to empty, grader will return 0.001
210
- else:
211
- print(f"[AUTONOMOUS SOLVING] Generated {len(fixed_config)} char fix for task={task_id}", flush=True)
212
- else:
213
- # Use provided fixed_config
214
- fixed_config = fc
215
- print(f"[PROVIDED CONFIG] Using submitted fix: {len(fixed_config)} chars", flush=True)
216
-
217
- # Run the grader (returns float for validator compatibility)
218
- grader_result = task.grader(fixed_config)
219
 
220
  # Convert to internal tuple format (reward, error_msg, bugs_fixed)
221
  if isinstance(grader_result, tuple):
@@ -226,12 +74,11 @@ class ConfigDebugEnvironment(Environment):
226
  error_message = ""
227
  bugs_fixed = []
228
 
229
- # DEBUG: Log raw grader output
230
  print(
231
- f"[GRADER RESULT] task={task_id} "
232
- f"reward={reward} "
233
- f"type={type(reward).__name__} "
234
- f"bugs_fixed_count={len(bugs_fixed)}",
235
  flush=True
236
  )
237
 
 
2
 
3
  Inherits from openenv.core.env_server.Environment and implements
4
  the standard reset/step/state interface with multi-task logic.
5
+
6
+ Note: This environment is for task/grading only.
7
+ LLM-based solving happens in inference.py (external runner).
8
  """
 
 
 
9
  from typing import Optional, Any
10
  from uuid import uuid4
11
 
 
12
  from openenv.core.env_server import Environment
13
  from server.models import ConfigDebugAction, ConfigDebugObservation, ConfigDebugState
14
  from server.tasks.task_registry import get_task, TASK_ORDER
15
 
16
  MAX_STEPS_PER_TASK = 5
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
  class ConfigDebugEnvironment(Environment):
20
  """Multi-task config debugging environment.
21
 
22
+ Manages tasks internally. Each WebSocket session
23
  (via create_fastapi_app) gets its own instance with independent state.
24
+
25
+ This environment ONLY handles task definitions and grading.
26
+ LLM solving is performed externally by inference.py.
27
  """
28
 
29
  SUPPORTS_CONCURRENT_SESSIONS = True
 
55
  return self._build_observation()
56
 
57
  def step(self, action: ConfigDebugAction, timeout_s: Optional[float] = None, **kwargs: Any) -> ConfigDebugObservation:
58
+ """Process an action: grade the submitted fixed_config."""
59
  if self._done:
60
  return self._build_observation()
61
 
62
  task_id = self._current_task_id()
63
  task = get_task(task_id)
64
 
65
+ # Run the grader on the submitted fixed_config
66
+ grader_result = task.grader(action.fixed_config)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
  # Convert to internal tuple format (reward, error_msg, bugs_fixed)
69
  if isinstance(grader_result, tuple):
 
74
  error_message = ""
75
  bugs_fixed = []
76
 
77
+ # Log grader result
78
  print(
79
+ f"[GRADER] task={task_id} "
80
+ f"reward={reward:.4f} "
81
+ f"bugs_fixed={len(bugs_fixed)}",
 
82
  flush=True
83
  )
84