Humanlearning commited on
Commit
c9ab476
·
1 Parent(s): f1cb55d

+ files fetching for the agent

Browse files
__pycache__/langraph_agent.cpython-313.pyc CHANGED
Binary files a/__pycache__/langraph_agent.cpython-313.pyc and b/__pycache__/langraph_agent.cpython-313.pyc differ
 
langraph_agent.py CHANGED
@@ -15,6 +15,7 @@ from langchain_core.messages import SystemMessage, HumanMessage
15
  from langchain_core.tools import tool
16
  from langchain.tools.retriever import create_retriever_tool
17
  from supabase.client import Client, create_client
 
18
 
19
  from langfuse.langchain import CallbackHandler
20
 
@@ -32,6 +33,9 @@ load_dotenv("env.local") # Try env.local as backup
32
  print(f"SUPABASE_URL loaded: {bool(os.environ.get('SUPABASE_URL'))}")
33
  print(f"GROQ_API_KEY loaded: {bool(os.environ.get('GROQ_API_KEY'))}")
34
 
 
 
 
35
  @tool
36
  def multiply(a: int, b: int) -> int:
37
  """Multiply two numbers.
@@ -240,21 +244,67 @@ def build_graph(provider: str = "groq"):
240
  if not state["messages"]:
241
  print("Retriever node: No messages in state")
242
  return {"messages": [sys_msg]}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
  if not vector_store:
 
 
 
244
  print("Retriever node: Vector store not available, skipping retrieval")
245
- return {"messages": [sys_msg] + state["messages"]}
246
- query_content = state["messages"][0].content
247
- print(f"Retriever node: Searching for similar questions with query: {query_content[:100]}...")
 
248
  similar_question = vector_store.similarity_search(query_content)
249
  print(f"Retriever node: Found {len(similar_question)} similar questions")
250
- if not similar_question:
 
 
 
 
 
251
  print("Retriever node: No similar questions found, proceeding without example")
252
- return {"messages": [sys_msg] + state["messages"]}
253
- example_msg = HumanMessage(
254
- content=f"Here I provide a similar question and answer for reference: \n\n{similar_question[0].page_content}",
255
- )
256
- print(f"Retriever node: Added example message from similar question")
257
- return {"messages": [sys_msg] + state["messages"] + [example_msg]}
 
258
  except Exception as e:
259
  print(f"Error in retriever node: {e}")
260
  return {"messages": [sys_msg] + state["messages"]}
 
15
  from langchain_core.tools import tool
16
  from langchain.tools.retriever import create_retriever_tool
17
  from supabase.client import Client, create_client
18
+ import requests # NEW: for HTTP requests to scoring API
19
 
20
  from langfuse.langchain import CallbackHandler
21
 
 
33
  print(f"SUPABASE_URL loaded: {bool(os.environ.get('SUPABASE_URL'))}")
34
  print(f"GROQ_API_KEY loaded: {bool(os.environ.get('GROQ_API_KEY'))}")
35
 
36
+ # Base URL of the scoring API (duplicated here to avoid circular import with basic_agent)
37
+ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
38
+
39
  @tool
40
  def multiply(a: int, b: int) -> int:
41
  """Multiply two numbers.
 
244
  if not state["messages"]:
245
  print("Retriever node: No messages in state")
246
  return {"messages": [sys_msg]}
247
+
248
+ # Extract the user query content early for downstream steps
249
+ query_content = state["messages"][0].content
250
+
251
+ # ------------------- NEW: fetch attachment if available -------------------
252
+ attachment_msg = None
253
+ try:
254
+ resp = requests.get(f"{DEFAULT_API_URL}/questions", timeout=30)
255
+ resp.raise_for_status()
256
+ questions = resp.json()
257
+ matched_task_id = None
258
+ for q in questions:
259
+ if str(q.get("question")).strip() == str(query_content).strip():
260
+ matched_task_id = str(q.get("task_id"))
261
+ break
262
+ if matched_task_id:
263
+ print(f"Retriever node: Found task_id {matched_task_id} for current question, attempting to download attachment…")
264
+ file_resp = requests.get(f"{DEFAULT_API_URL}/files/{matched_task_id}", timeout=60)
265
+ if file_resp.status_code == 200 and file_resp.content:
266
+ try:
267
+ file_text = file_resp.content.decode("utf-8", errors="replace")
268
+ except Exception:
269
+ file_text = "(binary or non-UTF8 file omitted)"
270
+ MAX_CHARS = 8000
271
+ if len(file_text) > MAX_CHARS:
272
+ print(f"Retriever node: Attachment length {len(file_text)} > {MAX_CHARS}, truncating…")
273
+ file_text = file_text[:MAX_CHARS] + "\n… (truncated)"
274
+ attachment_msg = HumanMessage(content=f"Attached file content for task {matched_task_id}:\n```python\n{file_text}\n```")
275
+ print("Retriever node: Prepared attachment message")
276
+ else:
277
+ print(f"Retriever node: No attachment found for task {matched_task_id} (status {file_resp.status_code})")
278
+ except Exception as api_e:
279
+ print(f"Retriever node: Error while fetching attachment – {api_e}")
280
+ # -------------------------------------------------------------------------
281
+
282
+ # If vector store unavailable, simply return sys_msg + user message (+ attachment if any)
283
  if not vector_store:
284
+ msgs = [sys_msg] + state["messages"]
285
+ if attachment_msg:
286
+ msgs.append(attachment_msg)
287
  print("Retriever node: Vector store not available, skipping retrieval")
288
+ return {"messages": msgs}
289
+
290
+ # Perform similarity search when vector store is available
291
+ print(f"Retriever node: Searching for similar questions with query: {query_content[:100]}…")
292
  similar_question = vector_store.similarity_search(query_content)
293
  print(f"Retriever node: Found {len(similar_question)} similar questions")
294
+ msgs = [sys_msg] + state["messages"]
295
+ if similar_question:
296
+ example_msg = HumanMessage(content=f"Here I provide a similar question and answer for reference: \n\n{similar_question[0].page_content}")
297
+ msgs.append(example_msg)
298
+ print("Retriever node: Added example message from similar question")
299
+ else:
300
  print("Retriever node: No similar questions found, proceeding without example")
301
+
302
+ # Attach the file content if we have it
303
+ if attachment_msg:
304
+ msgs.append(attachment_msg)
305
+ print("Retriever node: Added attachment content to messages")
306
+
307
+ return {"messages": msgs}
308
  except Exception as e:
309
  print(f"Error in retriever node: {e}")
310
  return {"messages": [sys_msg] + state["messages"]}
quick_specific_agent_test.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+ import tempfile
4
+ import requests
5
+ from basic_agent import BasicAgent, DEFAULT_API_URL
6
+ from langchain_core.messages import HumanMessage
7
+ from langfuse.langchain import CallbackHandler
8
+
9
+ # Initialize Langfuse CallbackHandler for LangGraph/Langchain (tracing)
10
+ try:
11
+ langfuse_handler = CallbackHandler()
12
+ except Exception as e:
13
+ print(f"Warning: Could not initialize Langfuse handler: {e}")
14
+ langfuse_handler = None
15
+
16
+ # Default Task ID (replace with your desired one or pass via CLI)
17
+ DEFAULT_TASK_ID = "f918266a-b3e0-4914-865d-4faa564f1aef"
18
+
19
+ def fetch_question_by_id(task_id: str, api_base: str = DEFAULT_API_URL):
20
+ """Return JSON of a question for a given task_id.
21
+
22
+ The scoring API does not (yet) expose an explicit /question/{id} endpoint,
23
+ so we fetch the full /questions list and filter locally. This works fine
24
+ because the list is small (<100 items).
25
+ """
26
+ try:
27
+ resp = requests.get(f"{api_base}/questions", timeout=30)
28
+ resp.raise_for_status()
29
+ questions = resp.json()
30
+ except Exception as e:
31
+ raise RuntimeError(f"Failed to fetch questions list: {e}") from e
32
+
33
+ for q in questions:
34
+ if str(q.get("task_id")) == str(task_id):
35
+ return q
36
+
37
+ raise ValueError(f"Task ID {task_id} not found in /questions list.")
38
+
39
+
40
+ def maybe_download_file(task_id: str, api_base: str = DEFAULT_API_URL) -> str | None:
41
+ """Try to download the file associated with a given task id. Returns local path or None."""
42
+ url = f"{api_base}/files/{task_id}"
43
+ try:
44
+ resp = requests.get(url, timeout=60)
45
+ if resp.status_code != 200:
46
+ print(f"No file associated with task {task_id} (status {resp.status_code}).")
47
+ return None
48
+ # Create temp file with same name from headers if available
49
+ filename = resp.headers.get("content-disposition", "").split("filename=")[-1].strip("\"") or f"{task_id}_attachment"
50
+ tmp_path = os.path.join(tempfile.gettempdir(), filename)
51
+ with open(tmp_path, "wb") as f:
52
+ f.write(resp.content)
53
+ print(f"Downloaded attachment to {tmp_path}")
54
+ return tmp_path
55
+ except requests.HTTPError as e:
56
+ print(f"Could not download file for task {task_id}: {e}")
57
+ except Exception as e:
58
+ print(f"Error downloading file: {e}")
59
+ return None
60
+
61
+
62
+ def main():
63
+ # Determine the task ID (CLI arg > env var > default)
64
+ task_id = (
65
+ sys.argv[1] if len(sys.argv) > 1 else os.environ.get("TASK_ID", DEFAULT_TASK_ID)
66
+ )
67
+ print(f"Using task ID: {task_id}")
68
+
69
+ q = fetch_question_by_id(task_id)
70
+ question_text = q["question"]
71
+
72
+ print("\n=== Specific Question ===")
73
+ print(f"Task ID : {task_id}")
74
+ print(f"Question: {question_text}")
75
+
76
+ # Attempt to get attachment if any
77
+ maybe_download_file(task_id)
78
+
79
+ # Run the agent
80
+ agent = BasicAgent()
81
+ result = agent.agent.invoke({"messages": [HumanMessage(content=question_text)]}, config={"callbacks": [langfuse_handler]})
82
+ if isinstance(result, dict) and "messages" in result and result["messages"]:
83
+ answer = result["messages"][-1].content.strip()
84
+ else:
85
+ answer = str(result)
86
+ print("\n=== Agent Answer ===")
87
+ print(answer)
88
+
89
+
90
+ if __name__ == "__main__":
91
+ main()