anonajay commited on
Commit
bd7cb81
Β·
verified Β·
1 Parent(s): ba0f45e

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. inference.py +21 -61
  2. server/app.py +26 -31
inference.py CHANGED
@@ -1,47 +1,3 @@
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 sys
@@ -53,7 +9,7 @@ from openai import OpenAI
53
  from dotenv import load_dotenv
54
 
55
  # --- PATH INJECTION ---
56
- # Ensures local 'client' and 'models' are prioritized over installed site-packages
57
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
58
 
59
  try:
@@ -68,11 +24,14 @@ load_dotenv()
68
  # --- CONFIGURATION ---
69
  # API_KEY is sourced from HF_TOKEN for hackathon compliance
70
  API_KEY = os.environ.get("HF_TOKEN") or os.environ.get("API_KEY")
71
- # Base URL for the Hugging Face Inference Router
72
- API_BASE_URL = os.environ.get("API_BASE_URL") or "https://router.huggingface.co/hf-inference/v1"
73
  MODEL_NAME = os.environ.get("MODEL_NAME") or "Qwen/Qwen2.5-72B-Instruct"
74
 
75
- # ADDRESS points to your Hugging Face Space API mount (/v1)
 
 
 
76
  ADDRESS = (os.environ.get("ADDRESS") or "https://anonajay-lint-coding-agent.hf.space/v1").rstrip("/")
77
 
78
  TASK_NAME = "multi-lang-lint-v1"
@@ -91,7 +50,7 @@ def log_start(task: str, env: str, model: str):
91
  print(f"[START] task={task} env={env} model={model}", flush=True)
92
 
93
  def log_step(step: int, action: str, reward: float, done: bool, error: Optional[str]):
94
- # Ensure action string is sanitized for single-line STDOUT compliance
95
  action_clean = str(action).replace("\n", " ").replace("\r", " ").strip()[:50]
96
  err_str = str(error).replace("\n", " ") if error else "null"
97
  print(f"[STEP] step={step} action={action_clean} reward={reward:.2f} done={str(done).lower()} error={err_str}", flush=True)
@@ -101,9 +60,8 @@ def log_end(success: bool, steps: int, score: float, rewards: List[float]):
101
  print(f"[END] success={str(success).lower()} steps={steps} score={score:.2f} rewards={rewards_str}", flush=True)
102
 
103
  async def main():
104
- # OpenAI client pointing to the Hugging Face Router
105
- # If 404 continues, ensure API_BASE_URL does not end in a slash.
106
- llm_client = OpenAI(base_url=API_BASE_URL.rstrip("/"), api_key=API_KEY)
107
 
108
  rewards, steps_taken, success = [], 0, False
109
  last_error = None
@@ -111,7 +69,7 @@ async def main():
111
  log_start(task=TASK_NAME, env=BENCHMARK, model=MODEL_NAME)
112
 
113
  try:
114
- # Connecting to the Environment Space
115
  async with LintCodingAgentEnv(
116
  base_url=ADDRESS,
117
  headers={
@@ -121,14 +79,14 @@ async def main():
121
  }
122
  ) as env:
123
 
124
- # 🏁 Level 1 Handshake (Reset)
125
  result = await env.reset()
126
 
127
  for step in range(1, MAX_STEPS + 1):
128
  obs = result.observation
129
  steps_taken = step
130
 
131
- # Context Construction
132
  user_prompt = (
133
  f"LEVEL: {obs.level}\n"
134
  f"LANGUAGE: {obs.language}\n"
@@ -136,7 +94,7 @@ async def main():
136
  f"OBJECTIVE: {obs.problem_statement}"
137
  )
138
 
139
- # LLM Inference with Wait-for-Model support
140
  completion = llm_client.chat.completions.create(
141
  model=MODEL_NAME,
142
  messages=[
@@ -149,7 +107,7 @@ async def main():
149
 
150
  action_text = (completion.choices[0].message.content or "").strip()
151
 
152
- # Step Transition (Action Execution)
153
  result = await env.step(LintCodingAgentAction(
154
  code_solution=action_text,
155
  explanation=f"Architect Fix: Level {obs.level}"
@@ -161,18 +119,20 @@ async def main():
161
  log_step(step, action_text, current_reward, result.done, None)
162
 
163
  if result.done:
164
- # Success logic based on clearing the 15-level sprint
165
  success = (sum(rewards) >= 1.0)
166
  break
167
 
168
  except Exception as e:
169
  last_error = str(e)
 
170
  log_step(steps_taken + 1, "execution_fault", 0.0, True, last_error)
171
 
172
  finally:
173
- # Score normalization [0, 1]
174
- total_score = sum(rewards) / len(rewards) if rewards else 0.0
175
- log_end(success, steps_taken, min(total_score, 1.0), rewards)
 
176
 
177
  if __name__ == "__main__":
178
  asyncio.run(main())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import asyncio
2
  import os
3
  import sys
 
9
  from dotenv import load_dotenv
10
 
11
  # --- PATH INJECTION ---
12
+ # Ensures local 'client' and 'models' are prioritized over installed packages
13
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
14
 
15
  try:
 
24
  # --- CONFIGURATION ---
25
  # API_KEY is sourced from HF_TOKEN for hackathon compliance
26
  API_KEY = os.environ.get("HF_TOKEN") or os.environ.get("API_KEY")
27
+
28
+ # MODEL IDENTIFIER
29
  MODEL_NAME = os.environ.get("MODEL_NAME") or "Qwen/Qwen2.5-72B-Instruct"
30
 
31
+ # API_BASE_URL: Set to the model-specific v1 endpoint to bypass Router 404s
32
+ API_BASE_URL = os.environ.get("API_BASE_URL") or f"https://api-inference.huggingface.co/models/{MODEL_NAME}/v1"
33
+
34
+ # ADDRESS: Points to your Hugging Face Space API mount (/v1)
35
  ADDRESS = (os.environ.get("ADDRESS") or "https://anonajay-lint-coding-agent.hf.space/v1").rstrip("/")
36
 
37
  TASK_NAME = "multi-lang-lint-v1"
 
50
  print(f"[START] task={task} env={env} model={model}", flush=True)
51
 
52
  def log_step(step: int, action: str, reward: float, done: bool, error: Optional[str]):
53
+ # Sanitize action string for single-line STDOUT compliance
54
  action_clean = str(action).replace("\n", " ").replace("\r", " ").strip()[:50]
55
  err_str = str(error).replace("\n", " ") if error else "null"
56
  print(f"[STEP] step={step} action={action_clean} reward={reward:.2f} done={str(done).lower()} error={err_str}", flush=True)
 
60
  print(f"[END] success={str(success).lower()} steps={steps} score={score:.2f} rewards={rewards_str}", flush=True)
61
 
62
  async def main():
63
+ # OpenAI client pointing to the model-specific Hugging Face endpoint
64
+ llm_client = OpenAI(base_url=API_BASE_URL, api_key=API_KEY)
 
65
 
66
  rewards, steps_taken, success = [], 0, False
67
  last_error = None
 
69
  log_start(task=TASK_NAME, env=BENCHMARK, model=MODEL_NAME)
70
 
71
  try:
72
+ # Connecting to the Environment Space with security headers
73
  async with LintCodingAgentEnv(
74
  base_url=ADDRESS,
75
  headers={
 
79
  }
80
  ) as env:
81
 
82
+ # 🏁 Initial Reset
83
  result = await env.reset()
84
 
85
  for step in range(1, MAX_STEPS + 1):
86
  obs = result.observation
87
  steps_taken = step
88
 
89
+ # Context Construction for the LLM
90
  user_prompt = (
91
  f"LEVEL: {obs.level}\n"
92
  f"LANGUAGE: {obs.language}\n"
 
94
  f"OBJECTIVE: {obs.problem_statement}"
95
  )
96
 
97
+ # LLM Inference with 'wait-for-model' to prevent 503/404 during cold starts
98
  completion = llm_client.chat.completions.create(
99
  model=MODEL_NAME,
100
  messages=[
 
107
 
108
  action_text = (completion.choices[0].message.content or "").strip()
109
 
110
+ # Execute Action via the Environment Bridge
111
  result = await env.step(LintCodingAgentAction(
112
  code_solution=action_text,
113
  explanation=f"Architect Fix: Level {obs.level}"
 
119
  log_step(step, action_text, current_reward, result.done, None)
120
 
121
  if result.done:
122
+ # Success is defined as clearing the cumulative reward threshold
123
  success = (sum(rewards) >= 1.0)
124
  break
125
 
126
  except Exception as e:
127
  last_error = str(e)
128
+ # Log the fault as a step to maintain sequence
129
  log_step(steps_taken + 1, "execution_fault", 0.0, True, last_error)
130
 
131
  finally:
132
+ # Final Score Calculation (Normalized to 0.00 - 1.00)
133
+ avg_reward = sum(rewards) / len(rewards) if rewards else 0.0
134
+ # If any step succeeded (reward 1.0), success should be true for the sprint
135
+ log_end(success, steps_taken, min(avg_reward, 1.0), rewards)
136
 
137
  if __name__ == "__main__":
138
  asyncio.run(main())
server/app.py CHANGED
@@ -17,7 +17,7 @@ logging.basicConfig(
17
  logger = logging.getLogger("ArchitectApp")
18
 
19
  # --- ARCHITECT'S PATH INJECTION ---
20
- # We force the root and server dirs into sys.path to ensure 'models' is found
21
  current_dir = os.path.dirname(os.path.abspath(__file__))
22
  project_root = os.path.abspath(os.path.join(current_dir, ".."))
23
 
@@ -32,12 +32,11 @@ except ImportError:
32
  from openenv.core.env_server.http_server import create_app
33
 
34
  # --- DOMAIN SPECIFIC IMPORTS ---
35
- # These are the schemas and logic we verified in previous steps
36
  from models import LintCodingAgentAction, LintCodingAgentObservation
37
  from server.lint_coding_agent_environment import LintCodingAgentEnvironment
38
 
39
  # --- APP FACTORY ---
40
- # 1. Create the environment logic app (The core OpenEnv engine)
41
  base_app = create_app(
42
  LintCodingAgentEnvironment,
43
  LintCodingAgentAction,
@@ -45,26 +44,30 @@ base_app = create_app(
45
  )
46
 
47
  # 2. Create the Main Wrapper App
48
- # redirect_slashes=False is CRITICAL to prevent 307 Redirect loops on HF
49
  app = FastAPI(
50
  title="AnonAjay Architect API",
51
  redirect_slashes=False
52
  )
53
 
54
  # --- DEBUG MIDDLEWARE ---
55
- # Real-time telemetry for every request hitting the Space
56
  @app.middleware("http")
57
  async def debug_logging(request: Request, call_next):
58
- logger.info(f"πŸ“‘ Request: {request.method} {request.url.path}")
59
  response = await call_next(request)
60
  logger.info(f"βœ… Outcome: {response.status_code}")
61
  return response
62
 
63
- # --- MOUNTING (The /v1 Fix) ---
64
- # This ensures that /v1/reset and /v1/ws are mapped to the core engine
 
 
 
 
 
65
  app.mount("/v1", base_app)
66
 
67
- # --- CORS SECURITY ---
68
  app.add_middleware(
69
  CORSMiddleware,
70
  allow_origins=["*"],
@@ -75,39 +78,31 @@ app.add_middleware(
75
 
76
  @app.get("/health")
77
  def health_check():
78
- """Simple health probe for Docker and HF status checks."""
79
- return {"status": "online", "message": "Lead Architect Server is Active", "port": 7860}
80
 
81
- # Catch-all for the root to prevent confusing 404s in the browser
82
  @app.get("/")
83
- def root_info():
 
84
  return {
85
- "message": "Lint Coding Agent API is Running",
86
- "endpoints": {
87
- "docs": "/v1/docs",
88
- "health": "/health",
89
- "api_root": "/v1"
90
- }
91
  }
92
 
93
  def main():
94
- """
95
- Entry point for the OpenEnv Server.
96
- Standardized to port 7860 for Hugging Face deployment.
97
- """
98
- parser = argparse.ArgumentParser()
99
- parser.add_argument("--host", type=str, default="0.0.0.0")
100
- parser.add_argument("--port", type=int, default=7860)
101
- args = parser.parse_args()
102
 
103
- logger.info(f"πŸš€ OpenEnv Sandbox Starting on {args.host}:{args.port}")
104
- logger.info(f"πŸ“ Geometry: /v1 mapped to OpenEnv Core")
105
 
106
  # proxy_headers + forwarded_allow_ips are vital for HF reverse proxy support
107
  uvicorn.run(
108
  app,
109
- host=args.host,
110
- port=args.port,
111
  proxy_headers=True,
112
  forwarded_allow_ips="*"
113
  )
 
17
  logger = logging.getLogger("ArchitectApp")
18
 
19
  # --- ARCHITECT'S PATH INJECTION ---
20
+ # Ensures 'models' and environment logic are discoverable regardless of the launch root
21
  current_dir = os.path.dirname(os.path.abspath(__file__))
22
  project_root = os.path.abspath(os.path.join(current_dir, ".."))
23
 
 
32
  from openenv.core.env_server.http_server import create_app
33
 
34
  # --- DOMAIN SPECIFIC IMPORTS ---
 
35
  from models import LintCodingAgentAction, LintCodingAgentObservation
36
  from server.lint_coding_agent_environment import LintCodingAgentEnvironment
37
 
38
  # --- APP FACTORY ---
39
+ # 1. Create the internal OpenEnv engine first
40
  base_app = create_app(
41
  LintCodingAgentEnvironment,
42
  LintCodingAgentAction,
 
44
  )
45
 
46
  # 2. Create the Main Wrapper App
47
+ # redirect_slashes=False is non-negotiable for Hugging Face Proxy stability
48
  app = FastAPI(
49
  title="AnonAjay Architect API",
50
  redirect_slashes=False
51
  )
52
 
53
  # --- DEBUG MIDDLEWARE ---
 
54
  @app.middleware("http")
55
  async def debug_logging(request: Request, call_next):
56
+ logger.info(f"πŸ“‘ Incoming: {request.method} {request.url.path}")
57
  response = await call_next(request)
58
  logger.info(f"βœ… Outcome: {response.status_code}")
59
  return response
60
 
61
+ # --- MOUNTING (The "Zero-Failure" Strategy) ---
62
+ # Explicitly map the root of /v1 to prevent the 404s seen in previous logs
63
+ @app.get("/v1")
64
+ async def v1_root():
65
+ return {"message": "OpenEnv API Root Active", "docs": "/v1/docs"}
66
+
67
+ # Mount the OpenEnv engine at /v1
68
  app.mount("/v1", base_app)
69
 
70
+ # --- CORS & HEALTH ---
71
  app.add_middleware(
72
  CORSMiddleware,
73
  allow_origins=["*"],
 
78
 
79
  @app.get("/health")
80
  def health_check():
81
+ """Heartbeat for Hugging Face and Docker health monitors."""
82
+ return {"status": "online", "port": 7860, "vfs_ready": True}
83
 
 
84
  @app.get("/")
85
+ def root_redirect():
86
+ """Provides a clear map for manual verification."""
87
  return {
88
+ "message": "Lead Architect Server Live",
89
+ "v1_docs": "/v1/docs",
90
+ "health": "/health"
 
 
 
91
  }
92
 
93
  def main():
94
+ """Standardized entry point for Hugging Face Spaces."""
95
+ # Use environment PORT or default to 7860
96
+ port = int(os.environ.get("PORT", 7860))
 
 
 
 
 
97
 
98
+ logger.info(f"πŸš€ Launching OpenEnv Sandbox on Port {port}")
99
+ logger.info(f"πŸ“ Geometry: /v1 mounted with redirect_slashes=False")
100
 
101
  # proxy_headers + forwarded_allow_ips are vital for HF reverse proxy support
102
  uvicorn.run(
103
  app,
104
+ host="0.0.0.0",
105
+ port=port,
106
  proxy_headers=True,
107
  forwarded_allow_ips="*"
108
  )