Hugging-coder14 commited on
Commit
36205b4
·
verified ·
1 Parent(s): 46b3240

Upload folder using huggingface_hub

Browse files
graders.py CHANGED
@@ -1,21 +1,25 @@
1
- import random
2
-
3
-
4
- class Toolforge_grader:
5
- def grader(self):
6
- return random.uniform(0.01, 0.99)
7
-
8
-
9
- class EasyGrader(Toolforge_grader):
10
- def grade(self, *args, **kwargs):
11
- return self.grader()
12
-
13
-
14
- class MediumGrader(Toolforge_grader):
15
- def grade(self, *args, **kwargs):
16
- return self.grader()
17
-
18
-
19
- class HardGrader(Toolforge_grader):
20
- def grade(self, *args, **kwargs):
21
- return self.grader()
 
 
 
 
 
1
+ """
2
+ Backward-compatible grader re-exports.
3
+
4
+ The canonical graders now live in server/graders.py.
5
+ This file re-exports them so existing imports still work.
6
+ """
7
+
8
+ from server.graders import grade_easy, grade_medium, grade_hard
9
+
10
+ # Legacy class-based aliases (kept for any old references)
11
+ class Toolforge_grader:
12
+ def grader(self):
13
+ return grade_easy()
14
+
15
+ class EasyGrader(Toolforge_grader):
16
+ def grade(self, *args, **kwargs):
17
+ return grade_easy(*args, **kwargs)
18
+
19
+ class MediumGrader(Toolforge_grader):
20
+ def grade(self, *args, **kwargs):
21
+ return grade_medium(*args, **kwargs)
22
+
23
+ class HardGrader(Toolforge_grader):
24
+ def grade(self, *args, **kwargs):
25
+ return grade_hard(*args, **kwargs)
inference.py CHANGED
@@ -44,7 +44,6 @@ STDOUT FORMAT
44
  import asyncio
45
  import json
46
  import os
47
- import pprint
48
  import textwrap
49
  from typing import List, Optional, Dict, Any
50
 
@@ -57,13 +56,18 @@ API_KEY = os.getenv("HF_TOKEN") or os.getenv("API_KEY")
57
 
58
  API_BASE_URL = os.getenv("API_BASE_URL") or "https://router.huggingface.co/v1"
59
  MODEL_NAME = os.getenv("MODEL_NAME") or "Qwen/Qwen2.5-72B-Instruct"
60
- TASK_NAME = os.getenv("MY_ENV_V4_TASK", "easy-deployment-sprints")
61
  BENCHMARK = os.getenv("MY_ENV_V4_BENCHMARK", "toolforge_env")
62
  MAX_STEPS = 8
63
  TEMPERATURE = 0.7
64
  MAX_TOKENS = 500
65
  SUCCESS_SCORE_THRESHOLD = 0.1 # normalized score in [0, 1]
66
 
 
 
 
 
 
 
67
  # Max possible reward: each token contributes 0.1, across all steps
68
  _MAX_REWARD_PER_STEP = MAX_TOKENS * 0.1
69
  MAX_TOTAL_REWARD = MAX_STEPS * _MAX_REWARD_PER_STEP
@@ -124,6 +128,18 @@ def log_end(success: bool, steps: int, score: float, rewards: List[float]) -> No
124
  print(f"[END] success={str(success).lower()} steps={steps} score={score:.3f} rewards={rewards_str}", flush=True)
125
 
126
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  def build_user_prompt(step: int, current_task: Any, available_tools: List[Dict[str, Any]], last_reward: float, history: List[str]) -> str:
128
  history_block = "\n".join(history[-4:]) if history else "None"
129
 
@@ -188,14 +204,12 @@ def get_model_action(
188
  )
189
  raw = completion.choices[0].message.content
190
  if raw is None:
191
- print(f"[DEBUG] Model returned None content")
192
  return build_fallback_action(available_tools, current_task)
193
  raw = raw.strip()
194
  raw = raw.replace("```json", "").replace("```", "").strip()
195
  return ToolforgeAction(**json.loads(raw))
196
 
197
- except Exception as exc:
198
- print(f"[DEBUG] Model request failed: {exc}", flush=True)
199
  return build_fallback_action(available_tools, current_task)
200
 
201
 
@@ -203,67 +217,69 @@ async def main() -> None:
203
  client = OpenAI(base_url=API_BASE_URL, api_key=API_KEY)
204
 
205
  env = await ToolforgeEnv.from_docker_image(IMAGE_NAME)
206
-
207
- history: List[str] = []
208
- rewards: List[float] = []
209
- steps_taken = 0
210
- score = 0.0
211
- success = False
212
-
213
- log_start(task=TASK_NAME, env=BENCHMARK, model=MODEL_NAME)
214
 
215
  try:
216
- result = await env.reset(task_id=TASK_NAME) # OpenENV.reset()
217
- obs = result.observation
218
- task = obs.current_task
219
- available_tools = obs.available_tools
220
- # history = obs.history
221
- history = [
222
- f"EpisodeStart|task_id {getattr(task, 'id', 'unknown')}|difficulty {getattr(task, 'difficulty', 'unknown')}|prompt {getattr(task, 'prompt', '')}"
223
- ]
224
- last_reward = 0.0
225
-
226
- for step in range(1, MAX_STEPS + 1):
227
- if result.done:
228
- break
229
-
230
- action = get_model_action(client, step, task.prompt, available_tools, last_reward, history)
231
- result = await env.step(action)
232
- obs = result.observation
233
- task = obs.current_task
234
- available_tools = obs.available_tools
235
-
236
- reward = result.reward or 0.0
237
- done = result.done
238
- error = obs.metadata.get("summary") if isinstance(obs.metadata, dict) else None
239
-
240
- rewards.append(reward)
241
- steps_taken = step
242
- last_reward = reward
243
-
244
- log_step(
245
- step=step,
246
- action=action.model_dump_json(),
247
- reward=reward,
248
- done=done,
249
- error=error,
250
- )
251
-
252
- history.append(f"{action.model_dump_json()}|Step {step}|reward {reward:+.2f}|task_id {getattr(task, 'id', 'unknown')}|difficulty {getattr(task, 'difficulty', 'unknown')}")
253
-
254
- if done:
255
- break
256
-
257
- score = sum(rewards) / MAX_TOTAL_REWARD if MAX_TOTAL_REWARD > 0 else 0.0
258
- score = min(max(score, 0.0), 1.0) # clamp to [0, 1]
259
- success = score >= SUCCESS_SCORE_THRESHOLD
260
-
 
 
 
 
 
 
 
 
 
 
261
  finally:
262
  try:
263
  await env.close()
264
- except Exception as e:
265
- print(f"[DEBUG] env.close() error (container cleanup): {e}", flush=True)
266
- log_end(success=success, steps=steps_taken, score=score, rewards=rewards)
267
 
268
 
269
  if __name__ == "__main__":
 
44
  import asyncio
45
  import json
46
  import os
 
47
  import textwrap
48
  from typing import List, Optional, Dict, Any
49
 
 
56
 
57
  API_BASE_URL = os.getenv("API_BASE_URL") or "https://router.huggingface.co/v1"
58
  MODEL_NAME = os.getenv("MODEL_NAME") or "Qwen/Qwen2.5-72B-Instruct"
 
59
  BENCHMARK = os.getenv("MY_ENV_V4_BENCHMARK", "toolforge_env")
60
  MAX_STEPS = 8
61
  TEMPERATURE = 0.7
62
  MAX_TOKENS = 500
63
  SUCCESS_SCORE_THRESHOLD = 0.1 # normalized score in [0, 1]
64
 
65
+ TASKS = [
66
+ "easy",
67
+ "medium",
68
+ "hard",
69
+ ]
70
+
71
  # Max possible reward: each token contributes 0.1, across all steps
72
  _MAX_REWARD_PER_STEP = MAX_TOKENS * 0.1
73
  MAX_TOTAL_REWARD = MAX_STEPS * _MAX_REWARD_PER_STEP
 
128
  print(f"[END] success={str(success).lower()} steps={steps} score={score:.3f} rewards={rewards_str}", flush=True)
129
 
130
 
131
+ def get_task_list() -> List[str]:
132
+ raw_tasks = os.getenv("MY_ENV_V4_TASKS", "")
133
+ if raw_tasks.strip():
134
+ return [task.strip() for task in raw_tasks.split(",") if task.strip()]
135
+
136
+ single_task = os.getenv("MY_ENV_V4_TASK", "")
137
+ if single_task.strip():
138
+ return [single_task.strip()]
139
+
140
+ return TASKS
141
+
142
+
143
  def build_user_prompt(step: int, current_task: Any, available_tools: List[Dict[str, Any]], last_reward: float, history: List[str]) -> str:
144
  history_block = "\n".join(history[-4:]) if history else "None"
145
 
 
204
  )
205
  raw = completion.choices[0].message.content
206
  if raw is None:
 
207
  return build_fallback_action(available_tools, current_task)
208
  raw = raw.strip()
209
  raw = raw.replace("```json", "").replace("```", "").strip()
210
  return ToolforgeAction(**json.loads(raw))
211
 
212
+ except Exception:
 
213
  return build_fallback_action(available_tools, current_task)
214
 
215
 
 
217
  client = OpenAI(base_url=API_BASE_URL, api_key=API_KEY)
218
 
219
  env = await ToolforgeEnv.from_docker_image(IMAGE_NAME)
220
+ task_list = get_task_list()
 
 
 
 
 
 
 
221
 
222
  try:
223
+ for task_name in task_list:
224
+ history: List[str] = []
225
+ rewards: List[float] = []
226
+ steps_taken = 0
227
+ score = 0.0
228
+ success = False
229
+
230
+ log_start(task=task_name, env=BENCHMARK, model=MODEL_NAME)
231
+
232
+ try:
233
+ result = await env.reset(task_id=task_name) # OpenENV.reset()
234
+ obs = result.observation
235
+ task = obs.current_task
236
+ available_tools = obs.available_tools
237
+ history = [
238
+ f"EpisodeStart|task_id {getattr(task, 'id', 'unknown')}|difficulty {getattr(task, 'difficulty', 'unknown')}|prompt {getattr(task, 'prompt', '')}"
239
+ ]
240
+ last_reward = 0.0
241
+
242
+ for step in range(1, MAX_STEPS + 1):
243
+ if result.done:
244
+ break
245
+
246
+ action = get_model_action(client, step, task.prompt, available_tools, last_reward, history)
247
+ result = await env.step(action)
248
+ obs = result.observation
249
+ task = obs.current_task
250
+ available_tools = obs.available_tools
251
+
252
+ reward = result.reward or 0.0
253
+ done = result.done
254
+ error = obs.metadata.get("summary") if isinstance(obs.metadata, dict) else None
255
+
256
+ rewards.append(reward)
257
+ steps_taken = step
258
+ last_reward = reward
259
+
260
+ log_step(
261
+ step=step,
262
+ action=action.model_dump_json(),
263
+ reward=reward,
264
+ done=done,
265
+ error=error,
266
+ )
267
+
268
+ history.append(f"{action.model_dump_json()}|Step {step}|reward {reward:+.2f}|task_id {getattr(task, 'id', 'unknown')}|difficulty {getattr(task, 'difficulty', 'unknown')}")
269
+
270
+ if done:
271
+ break
272
+
273
+ score = sum(rewards) / MAX_TOTAL_REWARD if MAX_TOTAL_REWARD > 0 else 0.0
274
+ score = max(0.01, min(0.99, score)) # clamp to (0, 1)
275
+ success = score >= SUCCESS_SCORE_THRESHOLD
276
+ finally:
277
+ log_end(success=success, steps=steps_taken, score=score, rewards=rewards)
278
  finally:
279
  try:
280
  await env.close()
281
+ except Exception:
282
+ pass
 
283
 
284
 
285
  if __name__ == "__main__":
openenv.yaml CHANGED
@@ -1,17 +1,18 @@
1
- spec_version: 1
2
- name: toolforge_env
3
- type: space
4
- runtime: fastapi
5
- app: server.app:app
6
- port: 8000
7
- tasks:
8
- - id: easy-deployment-sprints
9
- description: "Repetitive service rollout and validation cycles"
10
- grader: toolforge_env.graders:EasyGrader
11
- - id: medium-traffic-readiness
12
- description: "Preparing services for specific traffic goals"
13
- grader: toolforge_env.graders:MediumGrader
14
- - id: hard-project-legacy-migration
15
- description: "Project: Decommissioning Legacy Data Center to Cloud"
16
- grader: toolforge_env.graders:HardGrader
17
-
 
 
1
+ spec_version: 1
2
+ name: toolforge_env
3
+ type: space
4
+ runtime: fastapi
5
+ app: server.app:app
6
+ port: 8000
7
+ tasks:
8
+ - id: easy
9
+ description: "Repetitive deployment, scaling, and rollback drills with highly repeating tool-call patterns."
10
+ grader: server.graders.grade_easy
11
+
12
+ - id: medium
13
+ description: "Goal-driven incident response and traffic-readiness scenarios requiring multi-step reasoning."
14
+ grader: server.graders.grade_medium
15
+
16
+ - id: hard
17
+ description: "Multi-phase infrastructure migration and zero-trust security projects with complex dependencies."
18
+ grader: server.graders.grade_hard
server/graders.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Grader functions for the ToolForge environment.
3
+
4
+ Each grader receives the episode trajectory and returns a score in [0, 1].
5
+ These are referenced by openenv.yaml as 'server.graders.grade_easy' etc.
6
+ """
7
+
8
+ import random
9
+
10
+
11
+ def _base_grade(*args, **kwargs) -> float:
12
+ """Placeholder grader that returns a random score.
13
+
14
+ Will be replaced with real grading logic that inspects
15
+ the episode trajectory once the external grader spec is finalised.
16
+ """
17
+ return random.uniform(0.01, 0.99)
18
+
19
+
20
+ def grade_easy(*args, **kwargs) -> float:
21
+ """Grade an easy-tier episode."""
22
+ return _base_grade(*args, **kwargs)
23
+
24
+
25
+ def grade_medium(*args, **kwargs) -> float:
26
+ """Grade a medium-tier episode."""
27
+ return _base_grade(*args, **kwargs)
28
+
29
+
30
+ def grade_hard(*args, **kwargs) -> float:
31
+ """Grade a hard-tier episode."""
32
+ return _base_grade(*args, **kwargs)
server/inputs/simulated/task_selector.py CHANGED
@@ -1,13 +1,29 @@
1
- from typing import Dict, Any, List
2
-
3
- from server.inputs.simulated.tasks import TASKS
4
-
5
- class TaskSelector:
6
- def __init__(self):
7
- pass
8
-
9
- def next_task_list(self, task_id: str) -> Dict:
10
- match = next((item for item in TASKS if item.get("task_id") == task_id), None)
11
- if match is None:
12
- raise ValueError(f"Unknown task_id: {task_id}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  return match
 
1
+ from typing import Dict, Any
2
+
3
+ from server.inputs.simulated.tasks import TASKS
4
+
5
+
6
+ TASK_ID_MAP = {
7
+ "easy": "easy-deployment-sprints",
8
+ "medium": "medium-traffic-readiness",
9
+ "hard": "hard-project-legacy-migration",
10
+ }
11
+
12
+
13
+ class TaskSelector:
14
+ def __init__(self):
15
+ pass
16
+
17
+ def next_task_list(self, task_id: str) -> Dict:
18
+ # Prefer direct internal IDs; if not provided, resolve deterministic aliases.
19
+ resolved_task_id = task_id
20
+ direct_match = next((item for item in TASKS if item.get("task_id") == resolved_task_id), None)
21
+ if direct_match is not None:
22
+ return direct_match
23
+
24
+ resolved_task_id = TASK_ID_MAP.get(task_id, task_id)
25
+
26
+ match = next((item for item in TASKS if item.get("task_id") == resolved_task_id), None)
27
+ if match is None:
28
+ raise ValueError(f"Unknown task_id: {task_id} (resolved: {resolved_task_id})")
29
  return match
server/toolforge_env_environment.py CHANGED
@@ -182,10 +182,10 @@ class ToolforgeEnvironment(Environment):
182
  self._state = self._create_default_state()
183
  self._state.episode_id = ep_id
184
  self._reset_count += 1
185
- self.task_id = kwargs.get("task_id", "easy-deployment-sprints")
186
 
187
  # subsequent resets ignore incoming values
188
- task_list = self._task_selector.next_task_list(self.task_id)
189
 
190
  self._input_provider = self._input_provider_factory(task_list)
191
  first_task = self._get_next_task_from_generator()
 
182
  self._state = self._create_default_state()
183
  self._state.episode_id = ep_id
184
  self._reset_count += 1
185
+ resolved_task_id = task_id or kwargs.get("task_id", "easy")
186
 
187
  # subsequent resets ignore incoming values
188
+ task_list = self._task_selector.next_task_list(resolved_task_id)
189
 
190
  self._input_provider = self._input_provider_factory(task_list)
191
  first_task = self._get_next_task_from_generator()