ragavrida commited on
Commit
320d51b
Β·
1 Parent(s): 06850bc

fix: use only platform-injected API_BASE_URL and API_KEY for LiteLLM proxy

Browse files

- Remove model name variant fallback that could bypass proxy routing
- Remove HF_TOKEN/OPENAI_API_KEY fallbacks β€” only use API_KEY from platform
- Add startup proxy connectivity check
- Add verbose logging for every LLM call attempt
- Override OPENAI_API_KEY/OPENAI_BASE_URL env vars to prevent SDK auto-config
- Clean .env of all personal credentials

Files changed (1) hide show
  1. inference.py +94 -32
inference.py CHANGED
@@ -75,15 +75,31 @@ _load_dotenv(os.path.join(os.path.dirname(__file__), ".env"))
75
  # ─── Configuration ────────────────────────────────────────────────────────────
76
 
77
  IMAGE_NAME = os.getenv("LOCAL_IMAGE_NAME") or os.getenv("IMAGE_NAME") # If using from_docker_image()
78
- # The platform injects API_BASE_URL and API_KEY β€” use them directly with OpenAI client.
79
- API_BASE_URL = os.environ["API_BASE_URL"]
80
- API_KEY = os.environ["API_KEY"]
 
 
 
81
  MODEL_NAME = os.getenv("MODEL_NAME", "openai/gpt-4o-mini")
82
  BENCHMARK = "code-review-env"
83
  TEMPERATURE = 0.0
84
  MAX_TOKENS = 500
85
  SUCCESS_SCORE_THRESHOLD = 0.3
86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  # Debug: show which API config is active (stderr only)
88
  print(f"[DEBUG] API_BASE_URL = {API_BASE_URL}", file=sys.stderr, flush=True)
89
  print(f"[DEBUG] API_KEY value (last 8) = ...{API_KEY[-8:]}", file=sys.stderr, flush=True)
@@ -125,36 +141,55 @@ def log_end(success: bool, steps: int, score: float, rewards: List[float]) -> No
125
  # ─── LLM Interface ──────────────────────────────────────────────────────────
126
 
127
  def call_llm(client: OpenAI, system_prompt: str, user_prompt: str, max_retries: int = 3) -> str:
128
- """Call the LLM using OpenAI Client with retry. Returns response text."""
129
- model_candidates = [MODEL_NAME]
130
- if "/" in MODEL_NAME:
131
- model_candidates.append(MODEL_NAME.split("/", 1)[1])
 
 
 
 
132
 
133
  for attempt in range(max_retries):
134
- for model in model_candidates:
135
- try:
136
- completion = client.chat.completions.create(
137
- model=model,
138
- messages=[
139
- {"role": "system", "content": system_prompt},
140
- {"role": "user", "content": user_prompt},
141
- ],
142
- temperature=TEMPERATURE,
143
- max_tokens=MAX_TOKENS,
144
- stream=False,
145
- )
146
- return (completion.choices[0].message.content or "").strip()
147
- except Exception as exc:
148
- print(
149
- f"[DEBUG] Attempt {attempt+1}/{max_retries} failed (model={model}): {exc}",
150
- file=sys.stderr,
151
- flush=True,
152
- )
153
- # Try next candidate model (if any) before sleeping/retrying.
154
- continue
155
- if attempt < max_retries - 1:
156
- import time
157
- time.sleep(2 ** attempt)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  return ""
159
 
160
 
@@ -610,9 +645,36 @@ async def run_task(env: CodeReviewEnv, llm_client: OpenAI, task: str) -> float:
610
  # ─── Main ────────────────────────────────────────────────────────────────────
611
 
612
  async def main() -> int:
613
- # Initialize LLM client using the injected API_BASE_URL and API_KEY
 
614
  llm_client = OpenAI(base_url=API_BASE_URL, api_key=API_KEY)
615
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
616
  scores = {}
617
  space_url = os.getenv("SPACE_URL", "https://ragavrida-code-review-env.hf.space")
618
 
 
75
  # ─── Configuration ────────────────────────────────────────────────────────────
76
 
77
  IMAGE_NAME = os.getenv("LOCAL_IMAGE_NAME") or os.getenv("IMAGE_NAME") # If using from_docker_image()
78
+
79
+ # The platform injects API_BASE_URL and API_KEY at runtime.
80
+ # Do NOT fall back to personal credentials (HF_TOKEN, OPENAI_API_KEY) β€”
81
+ # all LLM calls MUST go through the platform's LiteLLM proxy.
82
+ API_BASE_URL = os.environ.get("API_BASE_URL", "")
83
+ API_KEY = os.environ.get("API_KEY", "")
84
  MODEL_NAME = os.getenv("MODEL_NAME", "openai/gpt-4o-mini")
85
  BENCHMARK = "code-review-env"
86
  TEMPERATURE = 0.0
87
  MAX_TOKENS = 500
88
  SUCCESS_SCORE_THRESHOLD = 0.3
89
 
90
+ if not API_BASE_URL:
91
+ print("[FATAL] API_BASE_URL is not set. The platform must inject this.", file=sys.stderr, flush=True)
92
+ sys.exit(1)
93
+ if not API_KEY:
94
+ print("[FATAL] API_KEY is not set. The platform must inject this.", file=sys.stderr, flush=True)
95
+ sys.exit(1)
96
+
97
+ # IMPORTANT: Override OPENAI_API_KEY and OPENAI_BASE_URL in the environment
98
+ # so the OpenAI SDK does NOT auto-configure from stale env vars.
99
+ # We always want to use our explicitly-set API_BASE_URL and API_KEY.
100
+ os.environ["OPENAI_API_KEY"] = API_KEY
101
+ os.environ["OPENAI_BASE_URL"] = API_BASE_URL
102
+
103
  # Debug: show which API config is active (stderr only)
104
  print(f"[DEBUG] API_BASE_URL = {API_BASE_URL}", file=sys.stderr, flush=True)
105
  print(f"[DEBUG] API_KEY value (last 8) = ...{API_KEY[-8:]}", file=sys.stderr, flush=True)
 
141
  # ─── LLM Interface ──────────────────────────────────────────────────────────
142
 
143
  def call_llm(client: OpenAI, system_prompt: str, user_prompt: str, max_retries: int = 3) -> str:
144
+ """Call the LLM using OpenAI Client with retry. Returns response text.
145
+
146
+ Uses ONLY the configured MODEL_NAME β€” no model name variants.
147
+ This ensures all requests go through the LiteLLM proxy with the
148
+ exact model name it expects.
149
+ """
150
+ import time
151
+ last_error = None
152
 
153
  for attempt in range(max_retries):
154
+ try:
155
+ print(
156
+ f"[DEBUG] LLM call attempt {attempt+1}/{max_retries} model={MODEL_NAME} base_url={client.base_url}",
157
+ file=sys.stderr,
158
+ flush=True,
159
+ )
160
+ completion = client.chat.completions.create(
161
+ model=MODEL_NAME,
162
+ messages=[
163
+ {"role": "system", "content": system_prompt},
164
+ {"role": "user", "content": user_prompt},
165
+ ],
166
+ temperature=TEMPERATURE,
167
+ max_tokens=MAX_TOKENS,
168
+ stream=False,
169
+ )
170
+ result = (completion.choices[0].message.content or "").strip()
171
+ print(
172
+ f"[DEBUG] LLM call succeeded, response length={len(result)}",
173
+ file=sys.stderr,
174
+ flush=True,
175
+ )
176
+ return result
177
+ except Exception as exc:
178
+ last_error = exc
179
+ print(
180
+ f"[DEBUG] Attempt {attempt+1}/{max_retries} failed (model={MODEL_NAME}): {exc}",
181
+ file=sys.stderr,
182
+ flush=True,
183
+ )
184
+ if attempt < max_retries - 1:
185
+ time.sleep(2 ** attempt)
186
+
187
+ # All retries exhausted β€” log loudly but don't crash the episode
188
+ print(
189
+ f"[ERROR] All {max_retries} LLM call attempts failed. Last error: {last_error}",
190
+ file=sys.stderr,
191
+ flush=True,
192
+ )
193
  return ""
194
 
195
 
 
645
  # ─── Main ────────────────────────────────────────────────────────────────────
646
 
647
  async def main() -> int:
648
+ # Initialize LLM client using the injected API_BASE_URL and API_KEY.
649
+ # Explicitly pass both to ensure all requests go through the LiteLLM proxy.
650
  llm_client = OpenAI(base_url=API_BASE_URL, api_key=API_KEY)
651
 
652
+ # ── Startup connectivity check ──────────────────────────────────────────
653
+ # Make a minimal LLM call to verify the proxy is reachable and the model
654
+ # name is valid. This ensures we fail loudly if something is misconfigured
655
+ # rather than silently falling back to default actions.
656
+ try:
657
+ print("[DEBUG] Testing LiteLLM proxy connectivity...", file=sys.stderr, flush=True)
658
+ test_completion = llm_client.chat.completions.create(
659
+ model=MODEL_NAME,
660
+ messages=[{"role": "user", "content": "ping"}],
661
+ max_tokens=5,
662
+ temperature=0.0,
663
+ )
664
+ print(
665
+ f"[DEBUG] Proxy connectivity OK β€” model={MODEL_NAME}, "
666
+ f"response={test_completion.choices[0].message.content!r}",
667
+ file=sys.stderr,
668
+ flush=True,
669
+ )
670
+ except Exception as e:
671
+ print(
672
+ f"[WARNING] Proxy connectivity test failed: {e}. "
673
+ f"Continuing anyway β€” LLM calls may fail.",
674
+ file=sys.stderr,
675
+ flush=True,
676
+ )
677
+
678
  scores = {}
679
  space_url = os.getenv("SPACE_URL", "https://ragavrida-code-review-env.hf.space")
680