mralamdari commited on
Commit
fe6ee07
·
verified ·
1 Parent(s): bb91d53

Update agent.py

Browse files
Files changed (1) hide show
  1. agent.py +57 -101
agent.py CHANGED
@@ -169,6 +169,7 @@ from transformers import Blip2Processor, Blip2ForConditionalGeneration
169
 
170
  from tavily import TavilyClient
171
 
 
172
  GPT_4o_API_KEY = os.environ["GPT_4o_API_KEY"]
173
  TAVILY_API_KEY = os.environ["TAVILY_API_KEY"]
174
  Pixtral12B_API = os.environ["Pixtral12B_API"]
@@ -183,24 +184,17 @@ model = ChatOpenAI(openai_api_key=GPT_4o_API_KEY,
183
  tavily = TavilyClient(api_key=TAVILY_API_KEY)
184
 
185
 
186
-
187
  # === 1. AGENT STATE ===
188
-
189
- class GaiaAgentState(TypedDict):
190
- task_id: int
191
- question: str
192
- files: List[str]
193
- level: int
194
- plan: List[Dict[str, Any]]
195
- tool_results: List[Any]
196
- final_answer: str
197
-
198
- # def input_parser(state: GaiaAgentState) -> dict:
199
- # return {
200
- # "question": state["question"],
201
- # "files": state.get("files", []),
202
- # "level": state.get("level", 1)
203
- # }
204
 
205
  # === 2. TOOL STUBS ===
206
 
@@ -259,11 +253,9 @@ def encode_image_to_base64(image_path):
259
  def vision_caption_via_api(image_path: str, max_length: Optional[int] = 64) -> str:
260
  """
261
  Generate a natural‑language caption for the image at `image_path`.
262
-
263
  Args:
264
  image_path: Local filesystem path (or URL fetched locally) to an image file.
265
  max_length: Maximum number of tokens in the generated caption (default: 64).
266
-
267
  Returns:
268
  A concise, human‑readable caption describing the image content.
269
  """
@@ -298,7 +290,7 @@ def vision_caption_via_api(image_path: str, max_length: Optional[int] = 64) -> s
298
  "messages": messages
299
  }
300
 
301
- response = requests.post(url, headers=headers, json=payload)
302
  response.raise_for_status()
303
 
304
  # The HF endpoint returns JSON like {"generated_text": "...caption..."}
@@ -360,11 +352,9 @@ TOOLS: Dict[str, Any] = {
360
  def planner_node(state: GaiaAgentState) -> dict:
361
  # Build metadata for each file
362
  files_metadata = []
363
- print(33333333333333, state)
364
- print(55555555555555,state['files'])
365
- for f_path in state['files']:
366
  # for f_path in state.files:
367
- print(5555555555555555555555555555555555555555555555555555555)
368
  mime, _ = mimetypes.guess_type(f_path)
369
  kind = "image" if mime and mime.startswith("image/") else "text"
370
  files_metadata.append({
@@ -373,9 +363,9 @@ def planner_node(state: GaiaAgentState) -> dict:
373
  })
374
 
375
  human_content = json.dumps({
376
- "question": state['question'],
377
  "files": files_metadata,
378
- "level": state['level']
379
  })
380
 
381
  messages = [
@@ -389,25 +379,23 @@ def planner_node(state: GaiaAgentState) -> dict:
389
 
390
  def tool_executor(state: GaiaAgentState) -> dict:
391
  tool_results = []
392
- for step in state['plan']:
393
  tool_obj = TOOLS[step["tool"]]
394
  out = tool_obj.run(tool_input=step["args"])
395
  tool_results.append(out)
396
- return {'tool_results': out}
397
 
398
 
399
  # ===== 2. The node implementation =====
400
  def synthesizer(state: GaiaAgentState) -> dict:
401
 
402
  # Format tool outputs as bullet points
403
- snippet_text = "\n".join(f"- {s}" for s in state["tool_results"])
404
 
405
  human_payload = f"""
406
- Question: {state['question']}
407
-
408
  Tool outputs:
409
  {snippet_text}
410
-
411
  Using the above, answer the question.
412
  """
413
  messages = [
@@ -432,26 +420,51 @@ def synthesizer(state: GaiaAgentState) -> dict:
432
  return {"final_answer": final}
433
 
434
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
435
 
436
- # === 4. BUILD & COMPILE GRAPH ===
437
- # agent.py
438
  class EsiAgent:
439
  def __init__(self):
440
  # 1. Build & compile your graph
441
  builder = StateGraph(GaiaAgentState)
442
 
443
- # builder.add_node("parse", input_parser)
444
  builder.add_node("planner", planner_node)
445
  builder.add_node("execute", tool_executor)
446
  builder.add_node("synthesize", synthesizer)
447
 
448
- # builder.add_edge(START, "parse")
449
- # builder.add_edge("parse", "planner")
450
- builder.add_edge(START, "planner")
451
  builder.add_edge("planner", "execute")
452
  builder.add_edge("execute", "synthesize")
453
  builder.add_edge("synthesize", END)
454
-
455
  self.graph = builder.compile()
456
 
457
 
@@ -462,75 +475,18 @@ class EsiAgent:
462
  files: optional list of file paths/URLs (default empty list)
463
  level: GAIA difficulty (1,2,3)
464
  """
465
- # 1) Build the raw_payload
466
- # print(11111111111, question)
467
  payload = {
468
- "task_id": None,
469
- "question": question,
470
- "files": files or [],
471
- "level": level
472
  }
473
- # initial = {
474
- # "question": question,
475
- # "files": [], # or your file list
476
- # "level": 1,
477
- # "task_id": 1,
478
- # "plan": [], # planner_node will overwrite this
479
- # "tool_results": [] # executor will overwrite this
480
- # "final_answer": ""
481
- # }
482
-
483
- # print(2222222222, payload)
484
-
485
- # 2) Wrap in your custom state class
486
  state = GaiaAgentState(raw_payload=payload)
487
- # state = GaiaAgentState(dict)
488
-
489
- # print(6666666666666, state)
490
- # 3) Invoke the graph end-to-end
491
  final_state = self.graph.invoke(state)
492
 
493
  # 4) Pull out the final answer
494
  return final_state.final_answer
495
-
496
-
497
- # final_state = graph.invoke({
498
- # "task_id": None,
499
- # "question": question,
500
- # "files": [],
501
- # "level": 1,
502
- # "plan": [],
503
- # "tool_results": [],
504
- # # plus any other initial keys your nodes expect
505
- # })
506
-
507
-
508
- # def run(self, question: str) -> str:
509
- # """
510
- # Runs the agent end‑to‑end on a single question string and returns
511
- # just the answer text (stripped of any prefix).
512
- # """
513
- # # Wrap in the same state shape your graph expects
514
- # payload = {
515
- # "task_id": None,
516
- # "question": question,
517
- # "files": [], # no attachments
518
- # "level": 1 # default to Level 1
519
- # }
520
- # # 2) Wrap in your state object
521
- # initial_state = GaiaAgentState(raw_payload=payload)
522
-
523
- # # initial_state = {"messages": [HumanMessage(content=question)]}
524
- # # Invoke the graph
525
- # final_state = self.graph.invoke(initial_state)
526
- # # Extract the last message
527
- # msgs = final_state["messages"]
528
- # last = msgs[-1].content
529
- # # If you prefix with "FINAL ANSWER: " remove that
530
- # if last.startswith("FINAL ANSWER:"):
531
- # return last[len("FINAL ANSWER:"):].strip()
532
- # return last.strip()
533
-
534
  # Optional: allow running agent.py directly for quick tests
535
  if __name__ == "__main__":
536
  agent = EsiAgent()
 
169
 
170
  from tavily import TavilyClient
171
 
172
+ # GPT_4o_API_KEY = os.environ["DeepSeek_API_KEY"]
173
  GPT_4o_API_KEY = os.environ["GPT_4o_API_KEY"]
174
  TAVILY_API_KEY = os.environ["TAVILY_API_KEY"]
175
  Pixtral12B_API = os.environ["Pixtral12B_API"]
 
184
  tavily = TavilyClient(api_key=TAVILY_API_KEY)
185
 
186
 
 
187
  # === 1. AGENT STATE ===
188
+ @dataclass
189
+ class GaiaAgentState:
190
+ raw_payload: Dict[str, Any]
191
+ question: str = ""
192
+ files: List[str] = field(default_factory=list)
193
+ level: int = 1
194
+ # downstream nodes can write into these:
195
+ plan: List[Dict[str,Any]] = field(default_factory=list)
196
+ tool_results: List[Any] = field(default_factory=list)
197
+ final_answer: str = ""
 
 
 
 
 
 
198
 
199
  # === 2. TOOL STUBS ===
200
 
 
253
  def vision_caption_via_api(image_path: str, max_length: Optional[int] = 64) -> str:
254
  """
255
  Generate a natural‑language caption for the image at `image_path`.
 
256
  Args:
257
  image_path: Local filesystem path (or URL fetched locally) to an image file.
258
  max_length: Maximum number of tokens in the generated caption (default: 64).
 
259
  Returns:
260
  A concise, human‑readable caption describing the image content.
261
  """
 
290
  "messages": messages
291
  }
292
 
293
+ response = requests.post(API_URL, headers=headers, json=payload)
294
  response.raise_for_status()
295
 
296
  # The HF endpoint returns JSON like {"generated_text": "...caption..."}
 
352
  def planner_node(state: GaiaAgentState) -> dict:
353
  # Build metadata for each file
354
  files_metadata = []
355
+ # print(55555555555555,state.files)
356
+ for f_path in state.files:
 
357
  # for f_path in state.files:
 
358
  mime, _ = mimetypes.guess_type(f_path)
359
  kind = "image" if mime and mime.startswith("image/") else "text"
360
  files_metadata.append({
 
363
  })
364
 
365
  human_content = json.dumps({
366
+ "question": state.question,
367
  "files": files_metadata,
368
+ "level": state.level
369
  })
370
 
371
  messages = [
 
379
 
380
  def tool_executor(state: GaiaAgentState) -> dict:
381
  tool_results = []
382
+ for step in state.plan:
383
  tool_obj = TOOLS[step["tool"]]
384
  out = tool_obj.run(tool_input=step["args"])
385
  tool_results.append(out)
386
+ return {'tool_results': tool_results}
387
 
388
 
389
  # ===== 2. The node implementation =====
390
  def synthesizer(state: GaiaAgentState) -> dict:
391
 
392
  # Format tool outputs as bullet points
393
+ snippet_text = "\n".join(f"- {s}" for s in state.tool_results)
394
 
395
  human_payload = f"""
396
+ Question: {state.question}
 
397
  Tool outputs:
398
  {snippet_text}
 
399
  Using the above, answer the question.
400
  """
401
  messages = [
 
420
  return {"final_answer": final}
421
 
422
 
423
+ # builder = StateGraph(dict)
424
+ from dataclasses import dataclass, field
425
+
426
+
427
+ @dataclass
428
+ class GaiaAgentState:
429
+ raw_payload: Dict[str, Any]
430
+ # these will get populated by the input_parser node:
431
+ question: str = ""
432
+ files: List[str] = field(default_factory=list)
433
+ level: int = 1
434
+ # downstream nodes can write into these:
435
+ plan: List[Dict[str,Any]] = field(default_factory=list)
436
+ tool_results: List[Any] = field(default_factory=list)
437
+ final_answer: str = ""
438
+
439
+
440
+
441
+
442
+ # 2) Input‑parser node: unpacks raw_payload→working state
443
+ def input_parser(state: GaiaAgentState) -> dict:
444
+ return {
445
+ "question": state.raw_payload["question"],
446
+ "files": state.raw_payload.get("files", []),
447
+ "level": state.raw_payload.get("level", 1),
448
+ }
449
+
450
+
451
+
452
 
 
 
453
  class EsiAgent:
454
  def __init__(self):
455
  # 1. Build & compile your graph
456
  builder = StateGraph(GaiaAgentState)
457
 
458
+ builder.add_node("parse", input_parser)
459
  builder.add_node("planner", planner_node)
460
  builder.add_node("execute", tool_executor)
461
  builder.add_node("synthesize", synthesizer)
462
 
463
+ builder.add_edge(START, "parse")
464
+ builder.add_edge("parse", "planner")
 
465
  builder.add_edge("planner", "execute")
466
  builder.add_edge("execute", "synthesize")
467
  builder.add_edge("synthesize", END)
 
468
  self.graph = builder.compile()
469
 
470
 
 
475
  files: optional list of file paths/URLs (default empty list)
476
  level: GAIA difficulty (1,2,3)
477
  """
478
+
 
479
  payload = {
480
+ "task_id": None,
481
+ "question": question,
482
+ "files": [],
483
+ "level": 1
484
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
485
  state = GaiaAgentState(raw_payload=payload)
 
 
 
 
486
  final_state = self.graph.invoke(state)
487
 
488
  # 4) Pull out the final answer
489
  return final_state.final_answer
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
490
  # Optional: allow running agent.py directly for quick tests
491
  if __name__ == "__main__":
492
  agent = EsiAgent()