Shardul Dhekane commited on
Commit
edaad73
·
1 Parent(s): 28ec988

Normalize provider-agnostic API config and add Space server endpoints

Browse files
Files changed (8) hide show
  1. Dockerfile +10 -34
  2. environment/tasks.py +2 -2
  3. inference.py +23 -6
  4. openenv.yaml +1 -0
  5. requirements.txt +2 -1
  6. server/__init__.py +0 -0
  7. server/app.py +76 -0
  8. submit.py +9 -3
Dockerfile CHANGED
@@ -12,38 +12,14 @@ RUN pip install --no-cache-dir -r requirements.txt
12
 
13
  COPY . .
14
 
15
- RUN echo '#!/bin/bash\n\
16
- if [ -z "$API_BASE_URL" ]; then\n\
17
- echo "ERROR: API_BASE_URL environment variable is required"\n\
18
- echo "Please set:"\n\
19
- echo " API_BASE_URL - Your API endpoint"\n\
20
- echo " MODEL_NAME - Model identifier"\n\
21
- echo " HF_TOKEN - Your Hugging Face / API key"\n\
22
- echo ""\n\
23
- echo "Examples:"\n\
24
- echo " OpenAI: API_BASE_URL=https://api.openai.com/v1 MODEL_NAME=gpt-4"\n\
25
- echo " Gemini: API_BASE_URL=https://generativelanguage.googleapis.com MODEL_NAME=gemini-1.5-pro"\n\
26
- echo " Local: API_BASE_URL=http://localhost:11434/v1 MODEL_NAME=llama2"\n\
27
- exit 1\n\
28
- fi\n\
29
- \n\
30
- if [ -z "$MODEL_NAME" ]; then\n\
31
- echo "ERROR: MODEL_NAME environment variable is required"\n\
32
- exit 1\n\
33
- fi\n\
34
- \n\
35
- if [ -z "$HF_TOKEN" ] && [ -z "$OPENAI_API_KEY" ] && [ -z "$API_KEY" ]; then\n\
36
- echo "ERROR: Missing auth token. Set HF_TOKEN (preferred) or OPENAI_API_KEY"\n\
37
- exit 1\n\
38
- fi\n\
39
- \n\
40
- echo "Configuration:"\n\
41
- echo " API_BASE_URL: ${API_BASE_URL}"\n\
42
- echo " MODEL_NAME: ${MODEL_NAME}"\n\
43
- echo " TEMPERATURE: ${TEMPERATURE:-0.7}"\n\
44
- echo " MAX_TOKENS: ${MAX_TOKENS:-2000}"\n\
45
- echo ""\n\
46
- \n\
47
- python inference.py "$@"' > /usr/local/bin/run-agent && chmod +x /usr/local/bin/run-agent
48
 
49
- CMD ["run-agent", "--task-id", "bug_detection_easy_1"]
 
 
 
 
12
 
13
  COPY . .
14
 
15
+ # Runtime API configuration (OpenAI-compatible):
16
+ # - API_BASE_URL is required
17
+ # - MODEL_NAME is required
18
+ # - API_KEY is canonical auth env var
19
+ # - HF_TOKEN and OPENAI_API_KEY are accepted as backward-compatible aliases
20
+ EXPOSE 7860
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
+ ENV HOST=0.0.0.0
23
+ ENV PORT=7860
24
+
25
+ CMD ["python", "-m", "server.app"]
environment/tasks.py CHANGED
@@ -60,7 +60,7 @@ class TaskDefinitions:
60
  "line_count": 4,
61
  "expected_issues": [
62
  {
63
- "line": 3,
64
  "type": "index_error",
65
  "severity": "medium",
66
  "description": "Index out of bounds when i is the last element"
@@ -128,7 +128,7 @@ def format_output(data):
128
  "line_count": 4,
129
  "expected_issues": [
130
  {
131
- "line": 3,
132
  "type": "performance",
133
  "severity": "medium",
134
  "description": "Inefficient string concatenation in loop"
 
60
  "line_count": 4,
61
  "expected_issues": [
62
  {
63
+ "line": 4,
64
  "type": "index_error",
65
  "severity": "medium",
66
  "description": "Index out of bounds when i is the last element"
 
128
  "line_count": 4,
129
  "expected_issues": [
130
  {
131
+ "line": 4,
132
  "type": "performance",
133
  "severity": "medium",
134
  "description": "Inefficient string concatenation in loop"
inference.py CHANGED
@@ -9,9 +9,19 @@ import sys
9
  from typing import Dict, Any
10
  from openai import OpenAI
11
 
 
 
 
 
 
 
 
 
 
 
12
  API_BASE_URL = os.environ.get("API_BASE_URL", "")
13
  MODEL_NAME = os.environ.get("MODEL_NAME", "")
14
- API_KEY = os.environ.get("HF_TOKEN") or os.environ.get("OPENAI_API_KEY") or os.environ.get("API_KEY", "")
15
  TEMPERATURE = float(os.environ.get("TEMPERATURE", "0.7"))
16
  MAX_TOKENS = int(os.environ.get("MAX_TOKENS", "2000"))
17
  REQUEST_TIMEOUT = int(os.environ.get("REQUEST_TIMEOUT", "60"))
@@ -21,18 +31,25 @@ if not API_BASE_URL:
21
  print("API Configuration Required")
22
  print("=" * 60)
23
  print("\nPlease set the following environment variables:\n")
24
- print(" API_BASE_URL - Your API endpoint")
25
  print(" MODEL_NAME - Model identifier")
26
- print(" HF_TOKEN - Your API key\n")
 
 
 
27
  print("Examples:\n")
 
 
 
 
28
  print(" Groq:")
29
  print(" export API_BASE_URL=https://api.groq.com/openai/v1")
30
  print(" export MODEL_NAME=llama-3.3-70b-versatile")
31
- print(" export HF_TOKEN=gsk_xxxxx\n")
32
  print(" Local Ollama:")
33
  print(" export API_BASE_URL=http://localhost:11434/v1")
34
  print(" export MODEL_NAME=llama3")
35
- print(" export HF_TOKEN=not-needed\n")
36
  print("=" * 60)
37
  sys.exit(1)
38
 
@@ -41,7 +58,7 @@ if not MODEL_NAME:
41
  sys.exit(1)
42
 
43
  if not API_KEY:
44
- print("ERROR: Missing auth token. Set HF_TOKEN (preferred) or OPENAI_API_KEY.")
45
  sys.exit(1)
46
 
47
  FALLBACK_ACTION = json.dumps({
 
9
  from typing import Dict, Any
10
  from openai import OpenAI
11
 
12
+
13
+ def resolve_api_key() -> str:
14
+ # Canonical env var is API_KEY, aliases are supported for compatibility.
15
+ return (
16
+ (os.environ.get("API_KEY") or "").strip()
17
+ or (os.environ.get("HF_TOKEN") or "").strip()
18
+ or (os.environ.get("OPENAI_API_KEY") or "").strip()
19
+ )
20
+
21
+
22
  API_BASE_URL = os.environ.get("API_BASE_URL", "")
23
  MODEL_NAME = os.environ.get("MODEL_NAME", "")
24
+ API_KEY = resolve_api_key()
25
  TEMPERATURE = float(os.environ.get("TEMPERATURE", "0.7"))
26
  MAX_TOKENS = int(os.environ.get("MAX_TOKENS", "2000"))
27
  REQUEST_TIMEOUT = int(os.environ.get("REQUEST_TIMEOUT", "60"))
 
31
  print("API Configuration Required")
32
  print("=" * 60)
33
  print("\nPlease set the following environment variables:\n")
34
+ print(" API_BASE_URL - OpenAI-compatible API endpoint")
35
  print(" MODEL_NAME - Model identifier")
36
+ print(" API_KEY - API key (canonical)\n")
37
+ print("Supported auth aliases (backward compatibility):")
38
+ print(" HF_TOKEN")
39
+ print(" OPENAI_API_KEY\n")
40
  print("Examples:\n")
41
+ print(" OpenAI:")
42
+ print(" export API_BASE_URL=https://api.openai.com/v1")
43
+ print(" export MODEL_NAME=gpt-4o-mini")
44
+ print(" export API_KEY=sk-xxxxx\n")
45
  print(" Groq:")
46
  print(" export API_BASE_URL=https://api.groq.com/openai/v1")
47
  print(" export MODEL_NAME=llama-3.3-70b-versatile")
48
+ print(" export API_KEY=gsk_xxxxx\n")
49
  print(" Local Ollama:")
50
  print(" export API_BASE_URL=http://localhost:11434/v1")
51
  print(" export MODEL_NAME=llama3")
52
+ print(" export API_KEY=not-needed\n")
53
  print("=" * 60)
54
  sys.exit(1)
55
 
 
58
  sys.exit(1)
59
 
60
  if not API_KEY:
61
+ print("ERROR: Missing auth token. Set API_KEY (preferred), or HF_TOKEN/OPENAI_API_KEY.")
62
  sys.exit(1)
63
 
64
  FALLBACK_ACTION = json.dumps({
openenv.yaml CHANGED
@@ -63,6 +63,7 @@ reward_range:
63
  max_episode_steps: 50
64
 
65
  requires_api_keys:
 
66
  - HF_TOKEN
67
  - OPENAI_API_KEY
68
  - API_BASE_URL
 
63
  max_episode_steps: 50
64
 
65
  requires_api_keys:
66
+ - API_KEY
67
  - HF_TOKEN
68
  - OPENAI_API_KEY
69
  - API_BASE_URL
requirements.txt CHANGED
@@ -7,4 +7,5 @@ pytest-cov>=4.0.0
7
  numpy>=1.24.0
8
  typing-extensions>=4.5.0
9
  requests>=2.31.0
10
- python-dotenv>=1.0.0
 
 
7
  numpy>=1.24.0
8
  typing-extensions>=4.5.0
9
  requests>=2.31.0
10
+ python-dotenv>=1.0.0
11
+ flask>=3.0.0
server/__init__.py ADDED
File without changes
server/app.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """HTTP server for running the code-review environment in a Space/container."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from threading import Lock
7
+ from typing import Any, Dict
8
+
9
+ from flask import Flask, jsonify, request
10
+
11
+ from environment.env import CodeReviewEnv
12
+
13
+
14
+ app = Flask(__name__)
15
+ _env = CodeReviewEnv()
16
+ _lock = Lock()
17
+
18
+
19
+ @app.get("/")
20
+ def root() -> Any:
21
+ return jsonify({
22
+ "status": "ok",
23
+ "service": "code-review-agent-env",
24
+ "endpoints": ["/health", "/reset", "/step", "/state"],
25
+ })
26
+
27
+
28
+ @app.get("/health")
29
+ def health() -> Any:
30
+ return jsonify({"status": "healthy"})
31
+
32
+
33
+ @app.route("/reset", methods=["GET", "POST"])
34
+ def reset() -> Any:
35
+ payload: Dict[str, Any] = request.get_json(silent=True) or {}
36
+ task_id = payload.get("task_id") or request.args.get("task_id")
37
+ with _lock:
38
+ obs = _env.reset(task_id=task_id)
39
+ return jsonify({"observation": obs})
40
+
41
+
42
+ @app.post("/step")
43
+ def step() -> Any:
44
+ payload = request.get_json(silent=True) or {}
45
+ action = payload.get("action")
46
+ if not isinstance(action, dict):
47
+ return jsonify({"error": "Request body must include an 'action' object"}), 400
48
+
49
+ with _lock:
50
+ observation, reward, done, info = _env.step(action)
51
+
52
+ return jsonify(
53
+ {
54
+ "observation": observation,
55
+ "reward": reward,
56
+ "done": done,
57
+ "info": info,
58
+ }
59
+ )
60
+
61
+
62
+ @app.get("/state")
63
+ def state() -> Any:
64
+ with _lock:
65
+ current_state = _env.state()
66
+ return jsonify(current_state)
67
+
68
+
69
+ def main() -> None:
70
+ host = os.getenv("HOST", "0.0.0.0")
71
+ port = int(os.getenv("PORT", "7860"))
72
+ app.run(host=host, port=port)
73
+
74
+
75
+ if __name__ == "__main__":
76
+ main()
submit.py CHANGED
@@ -25,7 +25,13 @@ CORE_TASKS = [
25
 
26
  def _run_cmd(command: List[str]) -> Tuple[int, str, str]:
27
  """Run a command and return (returncode, stdout, stderr)."""
28
- result = subprocess.run(command, capture_output=True, text=True)
 
 
 
 
 
 
29
  return result.returncode, result.stdout, result.stderr
30
 
31
 
@@ -118,9 +124,9 @@ def _inference_env_ready() -> Tuple[bool, str]:
118
  return False, "API_BASE_URL is not set"
119
  if not (os.getenv("MODEL_NAME") or "").strip():
120
  return False, "MODEL_NAME is not set"
121
- token = (os.getenv("HF_TOKEN") or os.getenv("OPENAI_API_KEY") or os.getenv("API_KEY") or "").strip()
122
  if not token:
123
- return False, "HF_TOKEN or OPENAI_API_KEY (or API_KEY fallback) is not set"
124
  return True, ""
125
 
126
 
 
25
 
26
  def _run_cmd(command: List[str]) -> Tuple[int, str, str]:
27
  """Run a command and return (returncode, stdout, stderr)."""
28
+ result = subprocess.run(
29
+ command,
30
+ capture_output=True,
31
+ text=True,
32
+ encoding="utf-8",
33
+ errors="replace",
34
+ )
35
  return result.returncode, result.stdout, result.stderr
36
 
37
 
 
124
  return False, "API_BASE_URL is not set"
125
  if not (os.getenv("MODEL_NAME") or "").strip():
126
  return False, "MODEL_NAME is not set"
127
+ token = (os.getenv("API_KEY") or os.getenv("HF_TOKEN") or os.getenv("OPENAI_API_KEY") or "").strip()
128
  if not token:
129
+ return False, "API_KEY is not set (supported aliases: HF_TOKEN, OPENAI_API_KEY)"
130
  return True, ""
131
 
132