Spaces:
Running
Running
File size: 10,417 Bytes
a23082c b8f6b7f a23082c b8f6b7f 114747f b8f6b7f a23082c b8f6b7f 114747f b8f6b7f 68bd1d5 b8f6b7f a23082c b8f6b7f a23082c 114747f a23082c 68bd1d5 a23082c b8f6b7f a23082c 114747f a23082c 114747f a23082c b8f6b7f a23082c |
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 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
import os
import logging
from llama_index.core.agent.workflow import ReActAgent
from llama_index.core.tools import FunctionTool
from llama_index.llms.google_genai import GoogleGenAI
from llama_index.llms.openai import OpenAI
# Setup logging
logger = logging.getLogger(__name__)
# Helper function to load prompt from file
def load_prompt_from_file(filename: str, default_prompt: str) -> str:
"""Loads a prompt from a text file."""
try:
# Assuming the prompt file is in the same directory as the agent script
script_dir = os.path.dirname(__file__)
prompt_path = os.path.join(script_dir, filename)
with open(prompt_path, "r") as f:
prompt = f.read()
logger.info(f"Successfully loaded prompt from {prompt_path}")
return prompt
except FileNotFoundError:
logger.warning(f"Prompt file {filename} not found at {prompt_path}. Using default.")
return default_prompt
except Exception as e:
logger.error(f"Error loading prompt file {filename}: {e}", exc_info=True)
return default_prompt
# --- Tool Function ---
def reasoning_tool_fn(context: str) -> str:
"""
Perform chain-of-thought reasoning over the provided context using a dedicated LLM.
Args:
context (str): The conversation/workflow history and current problem statement.
Returns:
str: A structured reasoning trace and conclusion, or an error message.
"""
logger.info(f"Executing reasoning tool with context length: {len(context)}")
# Configuration for the reasoning LLM (OpenAI in the original)
reasoning_llm_model = os.getenv("REASONING_LLM_MODEL", "gpt-4o-mini") # Use gpt-4o-mini as default
openai_api_key = os.getenv("OPENAI_API_KEY")
if not openai_api_key:
logger.error("ALPAFLOW_OPENAI_API_KEY not found for reasoning tool LLM.")
return "Error: ALPAFLOW_OPENAI_API_KEY must be set to use the reasoning tool."
# Define the prompt for the reasoning LLM
reasoning_prompt = f"""You are an expert reasoning engine. Analyze the following workflow context and problem statement:
--- CONTEXT START ---
{context}
--- CONTEXT END ---
Perform the following steps:
1. **Comprehension**: Identify the core question/problem and key constraints from the context.
2. **Decomposition**: Break the problem into logical sub-steps.
3. **Chain-of-Thought**: Reason through each sub-step, stating assumptions and deriving implications.
4. **Verification**: Check conclusions against constraints.
5. **Synthesis**: Integrate results into a cohesive answer/recommendation.
6. **Clarity**: Use precise language.
Respond with your numbered reasoning steps followed by a concise final conclusion or recommendation.
"""
try:
# Note: Original used OpenAI with a specific key and model. Retaining that.
# Consider adding `reasoning_effort="high"` if supported and desired.
llm = OpenAI(
model=reasoning_llm_model,
api_key=openai_api_key,
reasoning_effort="high",
temperature=0.055,
max_tokens=16384
)
logger.info(f"Using reasoning LLM: {reasoning_llm_model}")
response = llm.complete(reasoning_prompt)
logger.info("Reasoning tool execution successful.")
return response.text
except Exception as e:
logger.error(f"Error during reasoning tool LLM call: {e}", exc_info=True)
return f"Error during reasoning: {e}"
def answer_question(question: str) -> str:
"""
Answer any question by following this strict format:
1. Include your chain of thought (your reasoning steps).
2. End your reply with the exact template:
FINAL ANSWER: [YOUR FINAL ANSWER]
YOUR FINAL ANSWER must be:
- A number, or
- As few words as possible, or
- A comma-separated list of numbers and/or strings.
Formatting rules:
* If asked for a number, do not use commas or units (e.g., $, %), unless explicitly requested.
* If asked for a string, do not include articles or abbreviations (e.g., city names), and write digits in plain text.
* If asked for a comma-separated list, apply the above rules to each element.
This tool should be invoked immediately after completing the final planning sub-step.
"""
logger.info(f"Answering question: {question[:100]}")
gemini_api_key = os.getenv("GEMINI_API_KEY")
if not gemini_api_key:
logger.error("GEMINI_API_KEY not set for answer_question tool.")
return "Error: GEMINI_API_KEY not set."
model_name = os.getenv("ANSWER_TOOL_LLM_MODEL", "gemini-2.5-pro-preview-03-25")
# Build the assistant prompt enforcing the required format
assistant_prompt = (
"You are a general AI assistant. I will ask you a question. "
"Report your thoughts, and finish your answer with the following template: "
"FINAL ANSWER: [YOUR FINAL ANSWER]. "
"YOUR FINAL ANSWER should be a number OR as few words as possible "
"OR a comma separated list of numbers and/or strings. "
"If you are asked for a number, don't use commas for thousands or any units like $ or % unless specified. "
"If you are asked for a string, omit articles and abbreviations, and write digits in plain text. "
"If you are asked for a comma separated list, apply these rules to each element.\n\n"
f"Question: {question}\n"
"Answer:"
)
try:
llm = GoogleGenAI(api_key=gemini_api_key, model="gemini-2.5-pro-preview-03-25", temperature=0.05)
logger.info(f"Using answer LLM: {model_name}")
response = llm.complete(assistant_prompt)
logger.info("Answer generated successfully.")
return response.text
except Exception as e:
logger.error(f"LLM call failed during answer generation: {e}", exc_info=True)
return f"Error during answer generation: {e}"
# --- Tool Definition ---
reasoning_tool = FunctionTool.from_defaults(
fn=reasoning_tool_fn,
name="reasoning_tool",
description=(
"Applies detailed chain-of-thought reasoning to the provided workflow context using a dedicated LLM. "
"Input: context (str). Output: Reasoning steps and conclusion (str) or error message."
),
)
answer_question = FunctionTool.from_defaults(
fn=answer_question,
name="answer_question",
description=(
"Use this tool to answer any question, reporting your reasoning steps and ending with 'FINAL ANSWER: ...'. "
"Invoke this tool immediately after the final sub-step of planning is complete."
),
)
# --- Agent Initialization ---
def initialize_reasoning_agent() -> ReActAgent:
"""Initializes the Reasoning Agent."""
logger.info("Initializing ReasoningAgent...")
# Configuration for the agent's main LLM (Google GenAI)
agent_llm_model = os.getenv("REASONING_AGENT_LLM_MODEL", "gemini-2.5-pro-preview-03-25")
gemini_api_key = os.getenv("GEMINI_API_KEY")
if not gemini_api_key:
logger.error("GEMINI_API_KEY not found for ReasoningAgent.")
raise ValueError("GEMINI_API_KEY must be set for ReasoningAgent")
try:
llm = GoogleGenAI(api_key=gemini_api_key, model="gemini-2.5-pro-preview-03-25", temperature=0.05)
logger.info(f"Using agent LLM: {agent_llm_model}")
# Load system prompt
default_system_prompt = ("You are ReasoningAgent... [Default prompt content - replace with actual]" # Placeholder
)
system_prompt = load_prompt_from_file("../prompts/reasoning_agent_prompt.txt", default_system_prompt)
if system_prompt == default_system_prompt:
logger.warning("Using default/fallback system prompt for ReasoningAgent.")
agent = ReActAgent(
name="reasoning_agent",
description=(
"An autonomous reasoning specialist that applies `reasoning_tool` to perform "
"in-depth chain-of-thought analysis on incoming queries or contexts, "
"then seamlessly delegates the synthesized insights to `planner_agent` "
"or `long_context_management_agent` for subsequent task orchestration."
),
tools=[reasoning_tool],
llm=llm,
system_prompt=system_prompt,
can_handoff_to=[
"code_agent",
"research_agent",
"math_agent",
"role_agent",
"image_analyzer_agent",
"text_analyzer_agent",
"planner_agent",
"long_context_management_agent",
"advanced_validation_agent",
"video_analyzer_agent"
],
)
return agent
except Exception as e:
logger.error(f"Error during ReasoningAgent initialization: {e}", exc_info=True)
raise
# Example usage (for testing if run directly)
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger.info("Running reasoning_agent.py directly for testing...")
# Check required keys
required_keys = ["GEMINI_API_KEY", "ALPAFLOW_OPENAI_API_KEY"]
missing_keys = [key for key in required_keys if not os.getenv(key)]
if missing_keys:
print(f"Error: Required environment variable(s) not set: {', '.join(missing_keys)}. Cannot run test.")
else:
try:
# Test the reasoning tool directly
print("\nTesting reasoning_tool_fn...")
test_context = "User asked: What is the capital of France? ResearchAgent found: Paris. VerifierAgent confirmed: High confidence."
reasoning_output = reasoning_tool_fn(test_context)
print(f"Reasoning Tool Output:\n{reasoning_output}")
# Initialize the agent (optional)
# test_agent = initialize_reasoning_agent()
# print("\nReasoning Agent initialized successfully for testing.")
# Example chat (would require context passing mechanism)
# result = test_agent.chat("Synthesize the findings about the capital of France.")
# print(f"Agent chat result: {result}")
except Exception as e:
print(f"Error during testing: {e}")
|