Spaces:
Runtime error
Runtime error
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
- 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 |
-
|
| 79 |
-
API_BASE_URL
|
| 80 |
-
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 130 |
-
|
| 131 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
|
| 133 |
for attempt in range(max_retries):
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
)
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
|