Vishvam10 commited on
Commit
fb9d8e3
·
1 Parent(s): 17c0543

debug: (inference) sample script atleast ?!

Browse files
Files changed (1) hide show
  1. inference.py +142 -224
inference.py CHANGED
@@ -1,270 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import asyncio
2
- import json
3
  import os
4
- import sys
5
- import re
6
- from pathlib import Path
7
  from typing import List, Optional
8
- import httpx
9
- from dotenv import load_dotenv
10
- from openai import OpenAI
11
-
12
- ROOT = Path(__file__).resolve().parent
13
- REPO_ROOT = ROOT.parent
14
-
15
- if str(REPO_ROOT) not in sys.path:
16
- sys.path.insert(0, str(REPO_ROOT))
17
-
18
- load_dotenv()
19
 
20
- TASK_DIR = ROOT / "tasks"
21
- SYSTEM_PROMPT = (ROOT / "system_prompt.txt").read_text().strip()
22
-
23
- HF_TOKEN = os.getenv("HF_TOKEN") or os.getenv("API_KEY")
24
- MODEL_NAME = os.getenv("MODEL_NAME", "gpt-4o")
25
-
26
- BASE_URL = "https://vishvam10-cloudenv.hf.space"
27
-
28
- TASK_ORDER = ["easy-task", "medium-task", "hard-task"]
29
-
30
- MAX_PARSE_RETRIES = 3
31
- MAX_STEPS = 5
32
 
33
- client = OpenAI(base_url="https://api.openai.com/v1", api_key=HF_TOKEN)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
 
36
  def log_start(task: str, env: str, model: str) -> None:
37
  print(f"[START] task={task} env={env} model={model}", flush=True)
38
 
39
 
40
- def log_step(
41
- step: int, action: str, reward: float, done: bool, error: Optional[str]
42
- ) -> None:
43
  error_val = error if error else "null"
44
  done_val = str(done).lower()
45
- action_safe = action.replace("\n", " ").replace("\r", "")[:120]
46
  print(
47
- f"[STEP] step={step} action={action_safe} reward={reward:.2f} "
48
- f"done={done_val} error={error_val}",
49
  flush=True,
50
  )
51
 
52
 
53
- def log_end(
54
- success: bool, steps: int, score: float, rewards: List[float]
55
- ) -> None:
56
  rewards_str = ",".join(f"{r:.2f}" for r in rewards)
57
- print(
58
- f"[END] success={str(success).lower()} steps={steps} "
59
- f"score={score:.3f} rewards={rewards_str}",
60
- flush=True,
61
- )
62
-
63
 
64
- def load_task(name: str):
65
- return json.loads((TASK_DIR / f"{name}.json").read_text())
66
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
- async def register_pipeline(task: dict):
69
- async with httpx.AsyncClient(timeout=30) as http:
70
- r = await http.post(
71
- f"{BASE_URL}/api/pipelines",
72
- json={
73
- "pipeline_id": task["pipeline_id"],
74
- "broken_pipeline": task["broken_pipeline"],
75
- "ideal_pipeline": task["ideal_pipeline"],
76
- },
77
- )
78
-
79
- if r.status_code not in (200, 201, 400):
80
- print(
81
- f"[PIPELINE REGISTER ERROR] {r.status_code} {r.text}",
82
- flush=True,
83
- )
84
-
85
-
86
- async def env_reset(task_id: str, episode_id: str):
87
- async with httpx.AsyncClient(timeout=30) as http:
88
- r = await http.post(
89
- f"{BASE_URL}/reset",
90
- json={"task_id": task_id, "episode_id": episode_id},
91
- )
92
- r.raise_for_status()
93
- return r.json()
94
 
95
-
96
- async def env_step(action: dict):
97
- async with httpx.AsyncClient(timeout=30) as http:
98
- r = await http.post(
99
- f"{BASE_URL}/step",
100
- json={"action": action},
 
 
 
 
 
 
101
  )
102
- r.raise_for_status()
103
- return r.json()
 
 
 
104
 
105
 
106
- def clean_json(raw: str) -> str:
107
- raw = raw.strip()
108
- raw = re.sub(r"^```(?:json)?\s*", "", raw)
109
- raw = re.sub(r"\s*```$", "", raw)
110
 
111
- match = re.search(r"\{.*\}", raw, re.DOTALL)
112
- if match:
113
- return match.group(0)
114
 
115
- return raw
 
 
 
 
116
 
 
117
 
118
- def build_action(raw: str, task_id: str, episode_id: str):
119
  try:
120
- raw = clean_json(raw)
121
- data = json.loads(raw)
122
-
123
- if isinstance(data, dict) and "action" in data:
124
- data = data["action"]
125
-
126
- if not isinstance(data, dict):
127
- return None
128
-
129
- service = data.get("service")
130
- operation = data.get("operation")
131
-
132
- if not service or not operation:
133
- return None
134
 
135
- instance_id = data.get("instance_id")
 
 
136
 
137
- if isinstance(service, str) and ":" in service:
138
- service, parsed_instance = service.split(":", 1)
139
- instance_id = instance_id or parsed_instance
140
 
141
- return {
142
- "task_id": task_id,
143
- "episode_id": episode_id,
144
- "service": service.lower(),
145
- "instance_id": instance_id,
146
- "operation": operation.strip(),
147
- "payload": data.get("payload", {})
148
- if isinstance(data.get("payload"), dict)
149
- else {},
150
- "principal_arn": data.get("principal_arn"),
151
- "intent": data.get("intent"),
152
- }
153
 
154
- except Exception:
155
- return None
 
156
 
 
 
 
 
157
 
158
- def call_model(step, state, broken, ideal, history):
159
- prompt = f"""
160
- Return ONLY valid JSON.
161
-
162
- STEP {step}
163
- STATE {json.dumps(state)[:1000]}
164
- BROKEN {json.dumps(broken)[:1000]}
165
- IDEAL {json.dumps(ideal)[:1000]}
166
- HISTORY {history[-5:]}
167
- """
168
-
169
- res = client.chat.completions.create(
170
- model=MODEL_NAME,
171
- messages=[
172
- {"role": "system", "content": SYSTEM_PROMPT},
173
- {"role": "user", "content": prompt},
174
- ],
175
- temperature=0.3,
176
- max_tokens=500,
177
- )
178
-
179
- return (res.choices[0].message.content or "").strip()
180
-
181
-
182
- async def run_episode(task):
183
- task_id = task["pipeline_id"]
184
- episode_id = f"{task_id}-episode-1"
185
-
186
- log_start(task=task_id, env="http", model=MODEL_NAME)
187
-
188
- result = await env_reset(task_id, episode_id)
189
-
190
- await env_step(
191
- {
192
- "task_id": task_id,
193
- "episode_id": episode_id,
194
- "service": "internal",
195
- "instance_id": None,
196
- "operation": "InitializeEnvironment",
197
- "payload": {},
198
- }
199
- )
200
-
201
- await register_pipeline(task)
202
 
203
- obs = {}
204
- history = []
205
- rewards = []
206
- step_count = 0
207
 
208
- for step in range(MAX_STEPS):
209
- if obs.get("done"):
210
- break
211
 
212
- error = None
 
 
213
 
 
214
  try:
215
- raw = call_model(
216
- step,
217
- obs,
218
- task["broken_pipeline"],
219
- task["ideal_pipeline"],
220
- history,
221
- )
222
-
223
- action = build_action(raw, task_id, episode_id)
224
-
225
- if action is None:
226
- error = "invalid_action"
227
- log_step(step, "INVALID_ACTION", 0.0, False, error)
228
- continue
229
-
230
- result = await env_step(action)
231
- obs = result["observation"]
232
-
233
- reward = float(obs.get("reward", 0.0))
234
- done = bool(obs.get("done", False))
235
-
236
- rewards.append(reward)
237
- history.append(raw)
238
- step_count += 1
239
-
240
- log_step(
241
- step=step_count,
242
- action=str(action),
243
- reward=reward,
244
- done=done,
245
- error=None,
246
- )
247
-
248
  except Exception as e:
249
- error = str(e)
250
-
251
- log_step(step, "ERROR", 0.0, False, error)
252
- break
253
-
254
- if obs.get("done"):
255
- break
256
-
257
- success = obs.get("done", False)
258
- score = sum(rewards) / (len(rewards) or 1)
259
-
260
- log_end(success=success, steps=step_count, score=score, rewards=rewards)
261
-
262
-
263
- async def main():
264
- for name in TASK_ORDER:
265
- task = load_task(name)
266
- await run_episode(task)
267
 
268
 
269
  if __name__ == "__main__":
270
- asyncio.run(main())
 
1
+ """
2
+ Inference Script Example
3
+ ===================================
4
+ MANDATORY
5
+ - Before submitting, ensure the following variables are defined in your environment configuration:
6
+ API_BASE_URL The API endpoint for the LLM.
7
+ MODEL_NAME The model identifier to use for inference.
8
+ HF_TOKEN Your Hugging Face / API key.
9
+ LOCAL_IMAGE_NAME The name of the local image to use for the environment if you are using from_docker_image()
10
+ method
11
+
12
+ - Defaults are set only for API_BASE_URL and MODEL_NAME
13
+ (and should reflect your active inference setup):
14
+ API_BASE_URL = os.getenv("API_BASE_URL", "<your-active-endpoint>")
15
+ MODEL_NAME = os.getenv("MODEL_NAME", "<your-active-model>")
16
+
17
+ - The inference script must be named `inference.py` and placed in the root directory of the project
18
+ - Participants must use OpenAI Client for all LLM calls using above variables
19
+
20
+ STDOUT FORMAT
21
+ - The script must emit exactly three line types to stdout, in this order:
22
+
23
+ [START] task=<task_name> env=<benchmark> model=<model_name>
24
+ [STEP] step=<n> action=<action_str> reward=<0.00> done=<true|false> error=<msg|null>
25
+ [END] success=<true|false> steps=<n> score=<score> rewards=<r1,r2,...,rn>
26
+
27
+ Rules:
28
+ - One [START] line at episode begin.
29
+ - One [STEP] line per step, immediately after env.step() returns.
30
+ - One [END] line after env.close(), always emitted (even on exception).
31
+ - reward and rewards are formatted to 2 decimal places.
32
+ - done and success are lowercase booleans: true or false.
33
+ - error is the raw last_action_error string, or null if none.
34
+ - All fields on a single line with no newlines within a line.
35
+ - Each tasks should return score in [0, 1]
36
+
37
+ Example:
38
+ [START] task=click-test env=miniwob model=Qwen3-VL-30B
39
+ [STEP] step=1 action=click('123') reward=0.00 done=false error=null
40
+ [STEP] step=2 action=fill('456','text') reward=0.00 done=false error=null
41
+ [STEP] step=3 action=click('789') reward=1.00 done=true error=null
42
+ [END] success=true steps=3 score=1.00 rewards=0.00,0.00,1.00
43
+ """
44
+
45
  import asyncio
 
46
  import os
47
+ import textwrap
 
 
48
  from typing import List, Optional
 
 
 
 
 
 
 
 
 
 
 
49
 
50
+ from openai import OpenAI
 
 
 
 
 
 
 
 
 
 
 
51
 
52
+ from my_env_v4 import MyEnvV4Action, MyEnvV4Env
53
+ IMAGE_NAME = os.getenv("IMAGE_NAME") # If you are using docker image
54
+ API_KEY = os.getenv("HF_TOKEN") or os.getenv("API_KEY")
55
+
56
+ API_BASE_URL = os.getenv("API_BASE_URL") or "https://router.huggingface.co/v1"
57
+ MODEL_NAME = os.getenv("MODEL_NAME") or "Qwen/Qwen2.5-72B-Instruct"
58
+ TASK_NAME = os.getenv("MY_ENV_V4_TASK", "echo")
59
+ BENCHMARK = os.getenv("MY_ENV_V4_BENCHMARK", "my_env_v4")
60
+ MAX_STEPS = 8
61
+ TEMPERATURE = 0.7
62
+ MAX_TOKENS = 150
63
+ SUCCESS_SCORE_THRESHOLD = 0.1 # normalized score in [0, 1]
64
+
65
+ # Max possible reward: each token contributes 0.1, across all steps
66
+ _MAX_REWARD_PER_STEP = MAX_TOKENS * 0.1
67
+ MAX_TOTAL_REWARD = MAX_STEPS * _MAX_REWARD_PER_STEP
68
+
69
+ SYSTEM_PROMPT = textwrap.dedent(
70
+ """
71
+ You are interacting with a simple echo environment.
72
+ Each turn you must send a message. The environment will echo it back.
73
+ Reward is proportional to message length: reward = len(message) * 0.1
74
+ Your goal is to maximize total reward by sending meaningful, substantive messages.
75
+ Reply with exactly one message string — no quotes, no prefixes, just the message text.
76
+ """
77
+ ).strip()
78
 
79
 
80
  def log_start(task: str, env: str, model: str) -> None:
81
  print(f"[START] task={task} env={env} model={model}", flush=True)
82
 
83
 
84
+ def log_step(step: int, action: str, reward: float, done: bool, error: Optional[str]) -> None:
 
 
85
  error_val = error if error else "null"
86
  done_val = str(done).lower()
 
87
  print(
88
+ f"[STEP] step={step} action={action} reward={reward:.2f} done={done_val} error={error_val}",
 
89
  flush=True,
90
  )
91
 
92
 
93
+ def log_end(success: bool, steps: int, score: float, rewards: List[float]) -> None:
 
 
94
  rewards_str = ",".join(f"{r:.2f}" for r in rewards)
95
+ print(f"[END] success={str(success).lower()} steps={steps} score={score:.3f} rewards={rewards_str}", flush=True)
 
 
 
 
 
96
 
 
 
97
 
98
+ def build_user_prompt(step: int, last_echoed: str, last_reward: float, history: List[str]) -> str:
99
+ history_block = "\n".join(history[-4:]) if history else "None"
100
+ return textwrap.dedent(
101
+ f"""
102
+ Step: {step}
103
+ Last echoed message: {last_echoed!r}
104
+ Last reward: {last_reward:.2f}
105
+ Previous steps:
106
+ {history_block}
107
+ Send your next message.
108
+ """
109
+ ).strip()
110
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
 
112
+ def get_model_message(client: OpenAI, step: int, last_echoed: str, last_reward: float, history: List[str]) -> str:
113
+ user_prompt = build_user_prompt(step, last_echoed, last_reward, history)
114
+ try:
115
+ completion = client.chat.completions.create(
116
+ model=MODEL_NAME,
117
+ messages=[
118
+ {"role": "system", "content": SYSTEM_PROMPT},
119
+ {"role": "user", "content": user_prompt},
120
+ ],
121
+ temperature=TEMPERATURE,
122
+ max_tokens=MAX_TOKENS,
123
+ stream=False,
124
  )
125
+ text = (completion.choices[0].message.content or "").strip()
126
+ return text if text else "hello"
127
+ except Exception as exc:
128
+ print(f"[DEBUG] Model request failed: {exc}", flush=True)
129
+ return "hello"
130
 
131
 
132
+ async def main() -> None:
133
+ client = OpenAI(base_url=API_BASE_URL, api_key=API_KEY)
 
 
134
 
135
+ env = await MyEnvV4Env.from_docker_image(IMAGE_NAME)
 
 
136
 
137
+ history: List[str] = []
138
+ rewards: List[float] = []
139
+ steps_taken = 0
140
+ score = 0.0
141
+ success = False
142
 
143
+ log_start(task=TASK_NAME, env=BENCHMARK, model=MODEL_NAME)
144
 
 
145
  try:
146
+ result = await env.reset() # OpenENV.reset()
147
+ last_echoed = result.observation.echoed_message
148
+ last_reward = 0.0
 
 
 
 
 
 
 
 
 
 
 
149
 
150
+ for step in range(1, MAX_STEPS + 1):
151
+ if result.done:
152
+ break
153
 
154
+ message = get_model_message(client, step, last_echoed, last_reward, history)
 
 
155
 
156
+ result = await env.step(MyEnvV4Action(message=message))
157
+ obs = result.observation
 
 
 
 
 
 
 
 
 
 
158
 
159
+ reward = result.reward or 0.0
160
+ done = result.done
161
+ error = None
162
 
163
+ rewards.append(reward)
164
+ steps_taken = step
165
+ last_echoed = obs.echoed_message
166
+ last_reward = reward
167
 
168
+ log_step(step=step, action=message, reward=reward, done=done, error=error)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
 
170
+ history.append(f"Step {step}: {message!r} -> reward {reward:+.2f}")
 
 
 
171
 
172
+ if done:
173
+ break
 
174
 
175
+ score = sum(rewards) / MAX_TOTAL_REWARD if MAX_TOTAL_REWARD > 0 else 0.0
176
+ score = min(max(score, 0.0), 1.0) # clamp to [0, 1]
177
+ success = score >= SUCCESS_SCORE_THRESHOLD
178
 
179
+ finally:
180
  try:
181
+ await env.close()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  except Exception as e:
183
+ print(f"[DEBUG] env.close() error (container cleanup): {e}", flush=True)
184
+ log_end(success=success, steps=steps_taken, score=score, rewards=rewards)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
 
186
 
187
  if __name__ == "__main__":
188
+ asyncio.run(main())