GT5557 commited on
Commit
ca8b11b
Β·
verified Β·
1 Parent(s): 3799fdd

Update agent.py

Browse files
Files changed (1) hide show
  1. agent.py +82 -16
agent.py CHANGED
@@ -157,27 +157,37 @@ Produce the exact correct answer β€” nothing more, nothing less.
157
  - Use web_search for recent events, specific articles, prices, or anything time-sensitive.
158
  - Use fetch_page when a URL is provided or a search result points to a relevant page.
159
  - Use run_python for any arithmetic, counting, sorting, or data transformation.
160
- - Use run_python with pandas for Excel/CSV questions. The file path will appear
161
- in the question as [ATTACHED FILE: /tmp/<filename>] β€” use that exact path in
162
- pd.read_excel() or pd.read_csv(). Print the final value with print().
 
 
 
 
 
163
  - Use reverse_text only when asked to reverse a string.
164
  - You may use up to 5 tool calls. Stop as soon as you have a confident answer.
165
- - After 3 tool calls with no clear answer, stop searching and output your best guess as FINAL ANSWER.
166
  - When writing Python code, keep scripts under 50 lines. Never paste raw page content into a script.
167
 
168
  ## Answer format rules
169
  1. Output the raw value only β€” no explanation, no preamble.
170
- 2. If asked for a first name, output only the first name.
171
- 3. If asked for a surname, output only the surname.
172
  4. Numbers: digits only unless units were explicitly requested.
173
- 5. Lists: comma-separated on one line.
174
- 6. If you cannot find the answer after searching, output: N/A
175
- 7. Never abbreviate. Always write full words:
176
- - City/place names in full: "Ho Chi Minh City" not "HCMC", "Saint Petersburg" not "St. Petersburg"
177
- - Country names in full: "United States" not "US" or "USA", "United Kingdom" not "UK"
178
- - Names in full unless the question asks for only part: "Robert" not "Rob", "William" not "Wm."
179
- - Institutions in full: "Massachusetts Institute of Technology" not "MIT"
180
- - Exception: only use an abbreviation if the question itself uses it or explicitly asks for it.
 
 
 
 
 
181
 
182
  ## Required final line
183
  Always end your response with exactly:
@@ -208,7 +218,40 @@ def maybe_answer_direct(question: str) -> str | None:
208
 
209
 
210
  # ==========================================================
211
- # INVOKE β€” with fallback chain
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  # ==========================================================
213
 
214
  def invoke(messages: list) -> object:
@@ -219,6 +262,7 @@ def invoke(messages: list) -> object:
219
 
220
  seen: set[str] = set()
221
  first = True
 
222
 
223
  for model in FALLBACK_CHAIN:
224
  key = model.model_name
@@ -231,11 +275,33 @@ def invoke(messages: list) -> object:
231
  if not first:
232
  LAST_MODEL_FALLBACK = "Yes"
233
  first = False
234
- return model.bind_tools(TOOLS).invoke(messages)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  except Exception as e:
236
  LAST_MODEL_ERROR = str(e)
237
  continue
238
 
 
 
 
 
239
  raise RuntimeError(f"All models failed. Last error: {LAST_MODEL_ERROR}")
240
 
241
  # ==========================================================
 
157
  - Use web_search for recent events, specific articles, prices, or anything time-sensitive.
158
  - Use fetch_page when a URL is provided or a search result points to a relevant page.
159
  - Use run_python for any arithmetic, counting, sorting, or data transformation.
160
+ - Use run_python with pandas for Excel/CSV questions. When the question contains
161
+ [ATTACHED FILE DATA], that IS the file content as CSV text. Parse it with:
162
+ import pandas as pd, io
163
+ data = '<copy the CSV lines from the question here>'
164
+ df = pd.read_csv(io.StringIO(data))
165
+ Then compute and print() the answer.
166
+ - If the question says [ATTACHED FILE CONTENT], that is Python code. Run it with run_python directly
167
+ β€” copy the code exactly as given into the run_python tool and print the final output.
168
  - Use reverse_text only when asked to reverse a string.
169
  - You may use up to 5 tool calls. Stop as soon as you have a confident answer.
170
+ - After 3 tool calls with no clear answer, stop and output your best guess as FINAL ANSWER.
171
  - When writing Python code, keep scripts under 50 lines. Never paste raw page content into a script.
172
 
173
  ## Answer format rules
174
  1. Output the raw value only β€” no explanation, no preamble.
175
+ 2. If asked for a first name, output ONLY the first/given name β€” not the full name, not the surname.
176
+ 3. If asked for a surname or last name, output ONLY the family name β€” not the full name.
177
  4. Numbers: digits only unless units were explicitly requested.
178
+ 5. Lists: comma-separated on one line, no extra spaces after commas unless the question uses them.
179
+ 6. For subset/set questions (e.g. "subset of S involving..."), output only the elements, comma-separated.
180
+ 7. If you cannot find the answer after searching, output: N/A
181
+ 8. For discography questions: count studio albums only. Live albums, compilations, box sets do not count.
182
+ 9. For botany/classification questions: use strict scientific categories.
183
+ - Fruits (botanical): tomato, pepper, cucumber, avocado, squash, beans, corn kernels.
184
+ - Vegetables (botanical): true vegetables are leaves (lettuce, spinach), stems (celery), roots
185
+ (carrot, sweet potato), bulbs (onion), or flowers (broccoli, cauliflower).
186
+ - Do NOT confuse culinary and botanical definitions. A tomato is a fruit botanically.
187
+ 10. Never abbreviate. Always write full words:
188
+ - City/place names in full: "Ho Chi Minh City" not "HCMC", "Saint Petersburg" not "St. Petersburg"
189
+ - Country names in full: "United States" not "US" or "USA", "United Kingdom" not "UK"
190
+ - Exception: only use an abbreviation if the question itself uses it or explicitly asks for it.
191
 
192
  ## Required final line
193
  Always end your response with exactly:
 
218
 
219
 
220
  # ==========================================================
221
+ # ANSWER QUALITY CHECK β€” used by invoke to decide fallback
222
+ # ==========================================================
223
+
224
+ def _answer_looks_weak(result) -> bool:
225
+ """
226
+ Return True if the model's response content does not contain a usable
227
+ FINAL ANSWER β€” meaning we should try the next model in the chain.
228
+ Only applies when the model made NO tool calls (pure text response).
229
+ If tool calls are present, we let the graph continue normally.
230
+ """
231
+ # If the model wants to call tools, don't short-circuit β€” let the graph run
232
+ tool_calls = getattr(result, "tool_calls", None)
233
+ if tool_calls:
234
+ return False
235
+
236
+ content = getattr(result, "content", "") or ""
237
+ if not isinstance(content, str):
238
+ return False
239
+
240
+ # Check if a FINAL ANSWER line is present and non-empty
241
+ match = re.search(r"FINAL ANSWER:\s*(.+)", content, re.I | re.S)
242
+ if not match:
243
+ return True
244
+
245
+ answer = match.group(1).strip()
246
+ # Treat explicit N/A or empty as weak
247
+ if not answer or answer.lower() in ("n/a", "none", "unknown", ""):
248
+ return True
249
+
250
+ return False
251
+
252
+
253
+ # ==========================================================
254
+ # INVOKE β€” exception fallback + content-quality fallback
255
  # ==========================================================
256
 
257
  def invoke(messages: list) -> object:
 
262
 
263
  seen: set[str] = set()
264
  first = True
265
+ last_result = None
266
 
267
  for model in FALLBACK_CHAIN:
268
  key = model.model_name
 
275
  if not first:
276
  LAST_MODEL_FALLBACK = "Yes"
277
  first = False
278
+
279
+ result = model.bind_tools(TOOLS).invoke(messages)
280
+ last_result = result
281
+
282
+ # If the model wants tool calls, return immediately β€”
283
+ # the graph will handle the tool execution and loop back
284
+ tool_calls = getattr(result, "tool_calls", None)
285
+ if tool_calls:
286
+ return result
287
+
288
+ # No tool calls β€” check if the answer is actually useful
289
+ if not _answer_looks_weak(result):
290
+ return result
291
+
292
+ # Answer is weak (N/A or missing FINAL ANSWER) β€” try next model
293
+ LAST_MODEL_FALLBACK = "Yes"
294
+ LAST_MODEL_ERROR = f"weak answer from {key}"
295
+ continue
296
+
297
  except Exception as e:
298
  LAST_MODEL_ERROR = str(e)
299
  continue
300
 
301
+ # All models tried β€” return whatever the last one gave us
302
+ if last_result is not None:
303
+ return last_result
304
+
305
  raise RuntimeError(f"All models failed. Last error: {LAST_MODEL_ERROR}")
306
 
307
  # ==========================================================