File size: 5,128 Bytes
e04605e
b5adc16
e04605e
b5adc16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e04605e
 
 
b5adc16
 
e04605e
 
 
 
b5adc16
 
 
 
 
 
 
e04605e
b5adc16
 
 
 
e04605e
b5adc16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e04605e
b5adc16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e04605e
b5adc16
 
e04605e
b5adc16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import os
import re
import google.generativeai as genai
from tools import web_search, read_file_from_api, python_interpreter

# --- NEW, MORE ADVANCED REACT PROMPT ---
REACT_PROMPT = """
You are a state-of-the-art, helpful AI agent designed to solve complex, multi-step problems.

**Your Task:**
Your goal is to answer the user's question with 100% accuracy. To do this, you will operate in a loop of Thought, Action, and Observation. You must break down the problem into a series of smaller steps.

**Your Tools:**
You have access to the following tools. Choose ONE tool per turn.
1.  `web_search[query]`: Use this to find current information, facts, or to research topics.
2.  `read_file_from_api[task_id]`: Use this ONLY when the question or an agent note explicitly mentions an attached file. It reads the raw content of that file.
3.  `python_interpreter[code]`: Use this for all calculations, data processing, and complex logic.
    - **This tool is powerful.** It has the `pandas` and `openpyxl` libraries installed.
    - You can use it to analyze data from files. For example, after using `read_file_from_api`, you can pass the raw content into a Python script for processing.
    - For Excel files, it's often better to use `pandas.read_excel(file_url)` directly within the python tool, where `file_url` can be constructed from the task_id.

**Reasoning Process:**
1.  **Thought:** Carefully analyze the question. Identify the required information and devise a step-by-step plan.
2.  **Action:** Choose the appropriate tool and input to execute the current step of your plan. Your action MUST be in the format `Action: tool_name[input]`.
3.  **Observation:** You will receive the result of your action.
4.  **Repeat:** Analyze the observation and continue with the next step in your plan until you have the final answer.

**CRITICAL SUBMISSION RULE:**
When you have the final, definitive answer, you MUST format your response as:
`Final Answer: [The single, exact answer]`
The system will automatically extract only the text after this prefix for submission. Do not add any other text or explanation.

---
Here is the problem:
Question: {question}
"""

class GeminiAgent:
    def __init__(self):
        print("Initializing GeminiAgent (Advanced ReAct)...")
        # ... (init logic remains the same: api_key, model, tools)
        api_key = os.getenv("GEMINI_API_KEY")
        if not api_key:
            raise ValueError("GEMINI_API_KEY secret not found! Please set it in your Space's settings.")
        genai.configure(api_key=api_key)
        self.model = genai.GenerativeModel('gemini-2.5-pro')
        self.tools = {
            "web_search": web_search,
            "read_file_from_api": read_file_from_api,
            "python_interpreter": python_interpreter
        }
        print("GeminiAgent initialized successfully with model 'gemini-2.5-pro'.")


    # MODIFIED to accept task_id
    def __call__(self, question: str, task_id: str) -> str:
        prompt = REACT_PROMPT.format(question=question)
        
        # ReAct loop
        for turn in range(10): # Max 10 turns
            print(f"\n--- Turn {turn + 1} for Task ID: {task_id} ---\n")
            
            response = self.model.generate_content(prompt)
            if not response.parts:
                print("Warning: Model returned an empty response.")
                prompt += "\nObservation: The model returned an empty response. Please try again."
                continue
            
            response_text = response.text
            print(f"LLM Response:\n{response_text}\n")
            
            # Check for Final Answer
            final_answer_match = re.search(r"Final Answer: (.*)", response_text, re.DOTALL)
            if final_answer_match:
                answer = final_answer_match.group(1).strip()
                print(f"Final Answer extracted: '{answer}'")
                return answer

            # Look for an Action
            action_match = re.search(r"Action: (\w+)\[(.*)\]", response_text, re.DOTALL)
            if not action_match:
                observation = "No valid 'Action:' or 'Final Answer:' found. Please think step-by-step and select a tool or provide the final answer."
            else:
                tool_name = action_match.group(1).strip()
                tool_input = action_match.group(2).strip()
                
                if tool_name not in self.tools:
                    observation = f"Error: Unknown tool '{tool_name}'."
                else:
                    try:
                        # Pass the task_id to the tool function, which can then use it if needed
                        observation = self.tools[tool_name](tool_input if tool_name != 'read_file_from_api' else task_id)
                    except Exception as e:
                        observation = f"Error executing tool {tool_name}: {e}"
            
            print(f"Observation:\n{observation}\n")

            # Append the full turn to the prompt
            prompt += f"{response_text}\nObservation: {observation}\n"

        return "Agent failed to find an answer within 10 turns."