ErdemTheFixer commited on
Commit
20f2d56
·
verified ·
1 Parent(s): d7122a5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +204 -49
app.py CHANGED
@@ -2,17 +2,70 @@ import os
2
  import gradio as gr
3
  import requests
4
  import pandas as pd
5
- from typing import Optional, Dict, Any
 
 
 
 
6
 
 
7
  # --- Constants ---
8
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
9
 
 
10
 
11
  class LLMClient:
12
- # ... keep your existing __init__ ...
 
 
 
 
 
 
 
 
13
  def __init__(self):
14
  self.provider = (os.getenv("LLM_PROVIDER") or "openai").strip().lower()
15
- # ... existing provider init ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  self.max_retries = int(os.getenv("MAX_RETRIES", "8"))
17
  self.base_backoff = float(os.getenv("BASE_BACKOFF", "1.0")) # seconds
18
  self.max_backoff = float(os.getenv("MAX_BACKOFF", "30.0")) # cap
@@ -23,8 +76,7 @@ class LLMClient:
23
  for attempt in range(1, self.max_retries + 1):
24
  try:
25
  resp = requests.post(url, headers=headers, json=payload, timeout=timeout)
26
- if resp.status_code == 429:
27
- # Respect Retry-After if present
28
  retry_after = resp.headers.get("Retry-After")
29
  if retry_after:
30
  try:
@@ -33,14 +85,7 @@ class LLMClient:
33
  pass
34
  jitter = random.uniform(0, delay * 0.25)
35
  wait_s = min(delay + jitter, self.max_backoff)
36
- print(f"⏳ Rate limited (429). Attempt {attempt}/{self.max_retries}. Waiting {wait_s:.2f}s...")
37
- time.sleep(wait_s)
38
- delay = min(delay * 1.8, self.max_backoff)
39
- continue
40
- if resp.status_code in (500, 502, 503, 504):
41
- jitter = random.uniform(0, delay * 0.25)
42
- wait_s = min(delay + jitter, self.max_backoff)
43
- print(f"⏳ Server error {resp.status_code}. Attempt {attempt}/{self.max_retries}. Waiting {wait_s:.2f}s...")
44
  time.sleep(wait_s)
45
  delay = min(delay * 1.8, self.max_backoff)
46
  continue
@@ -56,18 +101,19 @@ class LLMClient:
56
  raise last_exc
57
  return requests.post(url, headers=headers, json=payload, timeout=timeout)
58
 
59
- def generate(self, prompt: str, max_tokens: int = 512, temperature: float = 0.6, top_p: float = 0.9) -> str:
60
  url = f"{self.base_url}/chat/completions"
61
  payload: Dict[str, Any] = {
62
  "model": self.model,
63
  "messages": [
64
- {"role": "system", "content": "You are a helpful, precise assistant."},
65
- {"role": "user", "content": prompt},
66
  ],
67
  "max_tokens": max_tokens,
68
  "temperature": temperature,
69
  "top_p": top_p,
70
  }
 
71
  try:
72
  resp = self._post_with_backoff(url, headers=self.headers, payload=payload, timeout=120)
73
  if resp.status_code == 404:
@@ -84,37 +130,145 @@ class LLMClient:
84
  except Exception as e:
85
  return f"Error: Unexpected failure while processing. Details: {e}"
86
 
 
87
 
88
- class BasicAgent:
89
  """
90
- Agent that delegates to a pluggable non-HF provider (OpenAI or Together).
 
 
91
  """
 
 
 
 
 
 
 
 
 
 
92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  def __init__(self):
94
- self.client = LLMClient()
95
- print(f"✅ BasicAgent initialized with provider: {self.client.provider}, model: {self.client.model}")
96
-
97
- def __call__(self, question: str, max_new_tokens: int = 512, temperature: float = 0.6, top_p: float = 0.9) -> str:
98
- print(f"📝 Agent received question (preview): {question[:80]}...")
99
- answer = self.client.generate(
100
- prompt=question,
101
- max_tokens=max_new_tokens,
102
- temperature=temperature,
103
- top_p=top_p,
 
 
104
  )
105
- print(f"🤖 Agent returning answer (preview): {answer[:80]}...")
106
- return answer
107
-
108
 
109
- def run_and_submit_all(profile: gr.OAuthProfile | None):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  """
111
  Fetches all questions, runs the BasicAgent on them, submits all answers,
112
  and displays the results.
113
  """
114
- space_id = os.getenv("SPACE_ID")
 
115
 
116
  if profile:
117
- username = f"{profile.username}"
118
  print(f"User logged in: {username}")
119
  else:
120
  print("User not logged in.")
@@ -124,13 +278,13 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
124
  questions_url = f"{api_url}/questions"
125
  submit_url = f"{api_url}/submit"
126
 
127
- # 1. Instantiate Agent
128
  try:
129
  agent = BasicAgent()
130
  except Exception as e:
131
  print(f"Error instantiating agent: {e}")
132
  return f"Error initializing agent: {e}", None
133
-
134
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
135
  print(agent_code)
136
 
@@ -141,16 +295,16 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
141
  response.raise_for_status()
142
  questions_data = response.json()
143
  if not questions_data:
144
- print("Fetched questions list is empty.")
145
- return "Fetched questions list is empty or invalid format.", None
146
  print(f"Fetched {len(questions_data)} questions.")
147
  except requests.exceptions.RequestException as e:
148
  print(f"Error fetching questions: {e}")
149
  return f"Error fetching questions: {e}", None
150
  except requests.exceptions.JSONDecodeError as e:
151
- print(f"Error decoding JSON response from questions endpoint: {e}")
152
- print(f"Response text: {response.text[:500]}")
153
- return f"Error decoding server response for questions: {e}", None
154
  except Exception as e:
155
  print(f"An unexpected error occurred fetching questions: {e}")
156
  return f"An unexpected error occurred fetching questions: {e}", None
@@ -159,7 +313,7 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
159
  results_log = []
160
  answers_payload = []
161
  print(f"Running agent on {len(questions_data)} questions...")
162
- for item in questions_data:
163
  task_id = item.get("task_id")
164
  question_text = item.get("question")
165
  if not task_id or question_text is None:
@@ -170,14 +324,14 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
170
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
171
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
172
  except Exception as e:
173
- print(f"Error running agent on task {task_id}: {e}")
174
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
175
 
176
  if not answers_payload:
177
  print("Agent did not produce any answers to submit.")
178
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
179
 
180
- # 4. Prepare Submission
181
  submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
182
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
183
  print(status_update)
@@ -232,11 +386,9 @@ with gr.Blocks() as demo:
232
  gr.Markdown(
233
  """
234
  **Instructions:**
235
-
236
  1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
237
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
238
  3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
239
-
240
  ---
241
  **Disclaimers:**
242
  Once clicking on the "submit button, it can take quite some time ( this is the time for the agent to go through all the questions).
@@ -249,6 +401,7 @@ with gr.Blocks() as demo:
249
  run_button = gr.Button("Run Evaluation & Submit All Answers")
250
 
251
  status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
 
252
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
253
 
254
  run_button.click(
@@ -258,8 +411,9 @@ with gr.Blocks() as demo:
258
 
259
  if __name__ == "__main__":
260
  print("\n" + "-"*30 + " App Starting " + "-"*30)
 
261
  space_host_startup = os.getenv("SPACE_HOST")
262
- space_id_startup = os.getenv("SPACE_ID")
263
 
264
  if space_host_startup:
265
  print(f"✅ SPACE_HOST found: {space_host_startup}")
@@ -267,7 +421,7 @@ if __name__ == "__main__":
267
  else:
268
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
269
 
270
- if space_id_startup:
271
  print(f"✅ SPACE_ID found: {space_id_startup}")
272
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
273
  print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
@@ -275,5 +429,6 @@ if __name__ == "__main__":
275
  print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
276
 
277
  print("-"*(60 + len(" App Starting ")) + "\n")
 
278
  print("Launching Gradio Interface for Basic Agent Evaluation...")
279
  demo.launch(debug=True, share=False)
 
2
  import gradio as gr
3
  import requests
4
  import pandas as pd
5
+ import time
6
+ import random
7
+ import re
8
+ import math
9
+ from typing import Dict, Any, List, Optional
10
 
11
+ # (Keep Constants as is)
12
  # --- Constants ---
13
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
14
 
15
+ # --- Provider-agnostic lightweight LLM client (no HF Inference API) ---
16
 
17
  class LLMClient:
18
+ """
19
+ Pluggable LLM client with robust 429/5xx backoff.
20
+ Supported providers via env LLM_PROVIDER:
21
+ - openai (OPENAI_API_KEY, model via OPENAI_MODEL, base via OPENAI_BASE_URL)
22
+ - together (TOGETHER_API_KEY, model via TOGETHER_MODEL, base via TOGETHER_BASE_URL)
23
+ - openrouter (OPENROUTER_API_KEY, model via OPENROUTER_MODEL, base fixed)
24
+ Defaults pick small reasoning-capable models.
25
+ """
26
+
27
  def __init__(self):
28
  self.provider = (os.getenv("LLM_PROVIDER") or "openai").strip().lower()
29
+
30
+ if self.provider == "openai":
31
+ self.api_key = os.getenv("OPENAI_API_KEY")
32
+ if not self.api_key:
33
+ raise ValueError("OPENAI_API_KEY is required when LLM_PROVIDER=openai.")
34
+ # Reasoning-lite default
35
+ self.model = os.getenv("OPENAI_MODEL", "gpt-4o-mini")
36
+ self.base_url = os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1")
37
+ self.headers = {
38
+ "Authorization": f"Bearer {self.api_key}",
39
+ "Content-Type": "application/json",
40
+ }
41
+
42
+ elif self.provider == "together":
43
+ self.api_key = os.getenv("TOGETHER_API_KEY")
44
+ if not self.api_key:
45
+ raise ValueError("TOGETHER_API_KEY is required when LLM_PROVIDER=together.")
46
+ self.model = os.getenv("TOGETHER_MODEL", "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo")
47
+ self.base_url = os.getenv("TOGETHER_BASE_URL", "https://api.together.xyz/v1")
48
+ self.headers = {
49
+ "Authorization": f"Bearer {self.api_key}",
50
+ "Content-Type": "application/json",
51
+ }
52
+
53
+ elif self.provider == "openrouter":
54
+ self.api_key = os.getenv("OPENROUTER_API_KEY")
55
+ if not self.api_key:
56
+ raise ValueError("OPENROUTER_API_KEY is required when LLM_PROVIDER=openrouter.")
57
+ # Strong, cost-effective default; change as desired
58
+ self.model = os.getenv("OPENROUTER_MODEL", "meta-llama/llama-3.1-8b-instruct:free")
59
+ self.base_url = "https://openrouter.ai/api/v1"
60
+ self.headers = {
61
+ "Authorization": f"Bearer {self.api_key}",
62
+ "Content-Type": "application/json",
63
+ }
64
+
65
+ else:
66
+ raise ValueError("LLM_PROVIDER must be one of: openai, together, openrouter")
67
+
68
+ # Backoff settings
69
  self.max_retries = int(os.getenv("MAX_RETRIES", "8"))
70
  self.base_backoff = float(os.getenv("BASE_BACKOFF", "1.0")) # seconds
71
  self.max_backoff = float(os.getenv("MAX_BACKOFF", "30.0")) # cap
 
76
  for attempt in range(1, self.max_retries + 1):
77
  try:
78
  resp = requests.post(url, headers=headers, json=payload, timeout=timeout)
79
+ if resp.status_code in (429, 500, 502, 503, 504):
 
80
  retry_after = resp.headers.get("Retry-After")
81
  if retry_after:
82
  try:
 
85
  pass
86
  jitter = random.uniform(0, delay * 0.25)
87
  wait_s = min(delay + jitter, self.max_backoff)
88
+ print(f"⏳ {self.provider} {resp.status_code}. Attempt {attempt}/{self.max_retries}. Waiting {wait_s:.2f}s...")
 
 
 
 
 
 
 
89
  time.sleep(wait_s)
90
  delay = min(delay * 1.8, self.max_backoff)
91
  continue
 
101
  raise last_exc
102
  return requests.post(url, headers=headers, json=payload, timeout=timeout)
103
 
104
+ def chat(self, system_prompt: str, user_prompt: str, max_tokens: int = 512, temperature: float = 0.6, top_p: float = 0.9) -> str:
105
  url = f"{self.base_url}/chat/completions"
106
  payload: Dict[str, Any] = {
107
  "model": self.model,
108
  "messages": [
109
+ {"role": "system", "content": system_prompt},
110
+ {"role": "user", "content": user_prompt},
111
  ],
112
  "max_tokens": max_tokens,
113
  "temperature": temperature,
114
  "top_p": top_p,
115
  }
116
+
117
  try:
118
  resp = self._post_with_backoff(url, headers=self.headers, payload=payload, timeout=120)
119
  if resp.status_code == 404:
 
130
  except Exception as e:
131
  return f"Error: Unexpected failure while processing. Details: {e}"
132
 
133
+ # --- Simple tool-use: safe-ish arithmetic and unit conversions ---
134
 
135
+ def maybe_compute_locally(question: str) -> Optional[str]:
136
  """
137
+ Lightweight math helper for common GAIA-style arithmetic/unit questions.
138
+ Avoids eval of arbitrary text; only allows digits, ops, dots, spaces, and parentheses.
139
+ Returns a computed answer string or None to defer to LLM.
140
  """
141
+ # Quick patterns: pure arithmetic, percents, simple ratios, sqrt, powers
142
+ text = question.strip().lower()
143
+
144
+ # Extract expression inside "calculate"/"compute"/"what is"
145
+ match = re.search(r"(?:calculate|compute|what is|evaluate)\s*[:\-]?\s*(.+)", text)
146
+ expr = match.group(1).strip() if match else text
147
+
148
+ # Replace common words to operators
149
+ expr = expr.replace("×", "*").replace("÷", "/").replace("^", "**")
150
+ expr = re.sub(r"(\d+)\s+percent", r"(\1/100)", expr)
151
 
152
+ # Allow only safe characters
153
+ if not re.fullmatch(r"[0-9\.\s\+\-\*\/\(\)\%]+", re.sub(r"\*\*", "**", expr)):
154
+ return None
155
+
156
+ # Disallow modulo for now (often not needed)
157
+ if "%" in expr:
158
+ return None
159
+
160
+ try:
161
+ # Use Python arithmetic safely
162
+ result = eval(expr, {"__builtins__": {}}, {"sqrt": math.sqrt, "pow": pow})
163
+ except Exception:
164
+ return None
165
+
166
+ if isinstance(result, float):
167
+ # Round to a reasonable precision
168
+ result = round(result, 6)
169
+ # normalize -0.0
170
+ if result == 0:
171
+ result = 0.0
172
+ return str(result)
173
+
174
+ # --- Basic Agent Definition ---
175
+ # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
176
+
177
+ class BasicAgent:
178
  def __init__(self):
179
+ # Config
180
+ self.rate_limit_s = float(os.getenv("RATE_LIMIT_SECONDS", "1.0"))
181
+ self.max_new_tokens = int(os.getenv("MAX_NEW_TOKENS", "256"))
182
+ self.samples = int(os.getenv("NUM_SAMPLES", "3")) # self-consistency votes
183
+ self.temperature = float(os.getenv("TEMPERATURE", "0.6"))
184
+ self.top_p = float(os.getenv("TOP_P", "0.9"))
185
+
186
+ # System prompt optimized for concise, correct answers
187
+ self.system_prompt = (
188
+ "You are a precise reasoning assistant. Answer with the final result only, "
189
+ "without extra explanations, unless the question explicitly asks for steps or justification. "
190
+ "Prefer exact values, otherwise numeric to a sensible precision. Be factual and avoid speculation."
191
  )
 
 
 
192
 
193
+ # LLM client (non-HF endpoints)
194
+ self.client = LLMClient()
195
+ print(f"BasicAgent initialized with provider={self.client.provider}, model={self.client.model}, samples={self.samples}")
196
+
197
+ def _finalize(self, text: str) -> str:
198
+ # Trim quotes, code fences, and whitespace
199
+ t = text.strip()
200
+ t = re.sub(r"^```.*?\n", "", t, flags=re.DOTALL) # remove starting fence if any
201
+ t = t.strip("` \n")
202
+ # Collapse multiple spaces
203
+ t = re.sub(r"\s+", " ", t)
204
+ return t.strip()
205
+
206
+ def _sample_answer(self, question: str) -> str:
207
+ # Try local compute first for arithmetic-like prompts
208
+ local = maybe_compute_locally(question)
209
+ if local is not None:
210
+ return local
211
+
212
+ # Otherwise query the LLM
213
+ reply = self.client.chat(
214
+ system_prompt=self.system_prompt,
215
+ user_prompt=question,
216
+ max_tokens=self.max_new_tokens,
217
+ temperature=self.temperature,
218
+ top_p=self.top_p,
219
+ )
220
+ return self._finalize(reply)
221
+
222
+ def __call__(self, question: str) -> str:
223
+ print(f"Agent received question (first 50 chars): {question[:50]}...")
224
+
225
+ # Self-consistency: multiple samples and vote
226
+ candidates: List[str] = []
227
+ for i in range(max(1, self.samples)):
228
+ ans = self._sample_answer(question)
229
+ candidates.append(ans)
230
+ print(f" sample {i+1}/{self.samples}: {ans[:100]}")
231
+ if i < self.samples - 1:
232
+ time.sleep(self.rate_limit_s)
233
+
234
+ # Majority vote by normalized string; numeric-aware normalization
235
+ normalized_counts: Dict[str, int] = {}
236
+ mapping: Dict[str, str] = {}
237
+
238
+ def normalize(s: str) -> str:
239
+ s_clean = s.strip().lower()
240
+ # Try extract number
241
+ num = re.findall(r"-?\d+(?:\.\d+)?", s_clean)
242
+ if len(num) == 1 and s_clean.replace(num[0], "").strip() in ["", "units", "unit"]:
243
+ try:
244
+ val = float(num[0])
245
+ return f"{round(val, 6)}"
246
+ except Exception:
247
+ pass
248
+ return s_clean
249
+
250
+ for c in candidates:
251
+ key = normalize(c)
252
+ normalized_counts[key] = normalized_counts.get(key, 0) + 1
253
+ # Keep first original for formatting
254
+ if key not in mapping:
255
+ mapping[key] = c
256
+
257
+ best_key = max(normalized_counts, key=normalized_counts.get)
258
+ final = mapping[best_key]
259
+ print(f"Agent returning answer: {final}")
260
+ return final
261
+
262
+ def run_and_submit_all( profile: gr.OAuthProfile | None):
263
  """
264
  Fetches all questions, runs the BasicAgent on them, submits all answers,
265
  and displays the results.
266
  """
267
+ # --- Determine HF Space Runtime URL and Repo URL ---
268
+ space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
269
 
270
  if profile:
271
+ username= f"{profile.username}"
272
  print(f"User logged in: {username}")
273
  else:
274
  print("User not logged in.")
 
278
  questions_url = f"{api_url}/questions"
279
  submit_url = f"{api_url}/submit"
280
 
281
+ # 1. Instantiate Agent ( modify this part to create your agent)
282
  try:
283
  agent = BasicAgent()
284
  except Exception as e:
285
  print(f"Error instantiating agent: {e}")
286
  return f"Error initializing agent: {e}", None
287
+ # In the case of an app running as a hugging Face space, this link points toward your codebase ( usefull for others so please keep it public)
288
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
289
  print(agent_code)
290
 
 
295
  response.raise_for_status()
296
  questions_data = response.json()
297
  if not questions_data:
298
+ print("Fetched questions list is empty.")
299
+ return "Fetched questions list is empty or invalid format.", None
300
  print(f"Fetched {len(questions_data)} questions.")
301
  except requests.exceptions.RequestException as e:
302
  print(f"Error fetching questions: {e}")
303
  return f"Error fetching questions: {e}", None
304
  except requests.exceptions.JSONDecodeError as e:
305
+ print(f"Error decoding JSON response from questions endpoint: {e}")
306
+ print(f"Response text: {response.text[:500]}")
307
+ return f"Error decoding server response for questions: {e}", None
308
  except Exception as e:
309
  print(f"An unexpected error occurred fetching questions: {e}")
310
  return f"An unexpected error occurred fetching questions: {e}", None
 
313
  results_log = []
314
  answers_payload = []
315
  print(f"Running agent on {len(questions_data)} questions...")
316
+ for idx, item in enumerate(questions_data, start=1):
317
  task_id = item.get("task_id")
318
  question_text = item.get("question")
319
  if not task_id or question_text is None:
 
324
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
325
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
326
  except Exception as e:
327
+ print(f"Error running agent on task {task_id}: {e}")
328
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
329
 
330
  if not answers_payload:
331
  print("Agent did not produce any answers to submit.")
332
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
333
 
334
+ # 4. Prepare Submission
335
  submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
336
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
337
  print(status_update)
 
386
  gr.Markdown(
387
  """
388
  **Instructions:**
 
389
  1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
390
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
391
  3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
 
392
  ---
393
  **Disclaimers:**
394
  Once clicking on the "submit button, it can take quite some time ( this is the time for the agent to go through all the questions).
 
401
  run_button = gr.Button("Run Evaluation & Submit All Answers")
402
 
403
  status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
404
+ # Removed max_rows=10 from DataFrame constructor
405
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
406
 
407
  run_button.click(
 
411
 
412
  if __name__ == "__main__":
413
  print("\n" + "-"*30 + " App Starting " + "-"*30)
414
+ # Check for SPACE_HOST and SPACE_ID at startup for information
415
  space_host_startup = os.getenv("SPACE_HOST")
416
+ space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
417
 
418
  if space_host_startup:
419
  print(f"✅ SPACE_HOST found: {space_host_startup}")
 
421
  else:
422
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
423
 
424
+ if space_id_startup: # Print repo URLs if SPACE_ID is found
425
  print(f"✅ SPACE_ID found: {space_id_startup}")
426
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
427
  print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
 
429
  print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
430
 
431
  print("-"*(60 + len(" App Starting ")) + "\n")
432
+
433
  print("Launching Gradio Interface for Basic Agent Evaluation...")
434
  demo.launch(debug=True, share=False)