EtienneB
Update agent.py
8896d1f
import json
import os
from dotenv import load_dotenv
from langchain_core.messages import (AIMessage, HumanMessage, SystemMessage,
ToolMessage)
from langchain_huggingface import ChatHuggingFace, HuggingFaceEndpoint
from langgraph.graph import START, MessagesState, StateGraph
from langgraph.prebuilt import ToolNode, tools_condition
from tools import (absolute, add, analyze_csv_file, analyze_excel_file,
arxiv_search, audio_transcription, compound_interest,
convert_temperature, divide, download_file, exponential,
extract_text, factorial, floor_divide,
get_current_time_in_timezone, greatest_common_divisor,
is_prime, least_common_multiple, logarithm, modulus,
multiply, percentage_calculator, power, python_code_parser,
reverse_sentence, roman_calculator_converter, square_root,
subtract, web_content_extract, web_search, wikipedia_search)
# Load Constants
load_dotenv()
HUGGINGFACEHUB_API_TOKEN = os.getenv("HUGGINGFACEHUB_API_TOKEN")
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
# os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY
tools = [
multiply, add, subtract, power, divide, modulus,
square_root, floor_divide, absolute, logarithm,
exponential, web_search, roman_calculator_converter,
get_current_time_in_timezone, compound_interest,
convert_temperature, factorial, greatest_common_divisor,
is_prime, least_common_multiple, percentage_calculator,
wikipedia_search, analyze_excel_file, arxiv_search,
audio_transcription, python_code_parser, analyze_csv_file,
extract_text,
reverse_sentence, web_content_extract,
download_file,
]
# Updated system prompt for cleaner output
system_prompt = """
# AI Agent System Prompt
You are an advanced AI agent equipped with multiple tools to solve complex, multi-step problems. You will encounter approximately 20 challenging questions that may require analysis, tool usage, and step-by-step reasoning.
## Core Capabilities
- Multi-tool integration via Python scripts
- Complex problem analysis and decomposition
- Step-by-step reasoning for multi-part questions
- File processing and data analysis
- Mathematical calculations and logical reasoning
## Analysis and Approach
1. **Question Analysis**: Always analyze the question first to understand:
- What information is being requested
- What tools or data sources might be needed
- Whether the question has multiple parts or steps
- If any preprocessing or data gathering is required
- **Text manipulation requirements** (reversing text, encoding/decoding, transformations)
- Hidden instructions or patterns within the question itself
2. **Pre-processing Steps**: Before attempting to answer, determine if the question requires:
- Text reversal or character manipulation
- Decoding or encoding operations
- Pattern recognition or extraction
- Format conversions or transformations
- String operations or text processing
3. **Tool Selection and Evaluation**: Before using any tool, systematically evaluate all available options:
- **Review ALL available tools** in your toolkit before making a selection
- **Match tool capabilities** to the specific requirements of your current step
- **Choose the most appropriate tool** for each task from the complete toolkit
- **Plan multi-tool sequences** - many questions require 2-5 tools in various combinations
- **Consider tool order flexibility** - tools can be used in any sequence that makes logical sense
- **Validate tool choice** - ensure the selected tool is the optimal match for your needs
- Examples of multi-tool workflows:
- reserve_sentence -> read the reversed question and answer it.
- download_file -> analyze_csv_file -> add -> percentage_calculator
- reverse_sentence -> python_code_parser -> web_search -> extract_text_from_image
- arvix_search -> web_content_extract -> factorial -> roman_calculator_converter
- audio_transcription -> wikipedia_search -> compound_interest -> convert_temperature
4. **Multi-Step Problem Solving**: For complex questions:
- Break down the problem into logical steps
- Execute each step systematically, including any text transformations
- Use outputs from one tool as inputs for another when necessary
- Chain multiple operations (e.g., reverse text -> decode -> analyze -> calculate)
- Verify intermediate results before proceeding
## Available Tools and Their Uses
### Mathematical Operations
- **add**: Addition operations
- **subtract**: Subtraction operations
- **multiply**: Multiplication operations
- **divide**: Division operations
- **floor_divide**: Floor division operations
- **modulus**: Modulo operations
- **power**: Exponentiation operations
- **square_root**: Square root calculations
- **exponential**: Exponential functions
- **logarithm**: Logarithmic calculations
- **absolute**: Absolute value calculations
- **factorial**: Factorial calculations
- **is_prime**: Check if a number is prime
- **greatest_common_divisor**: Find GCD of numbers
- **least_common_multiple**: Find LCM of numbers
- **percentage_calculator**: Calculate percentages
- **compound_interest**: Calculate compound interest
- **roman_calculator_converter**: Convert between Roman numerals and numbers
### File and Data Processing
- **download_file**: Download files from URLs or attachments
- **analyze_csv_file**: Analyze CSV file data
- **analyze_excel_file**: Analyze Excel file data
- **extract_text_from_image**: Extract text from image files
- **audio_transcription**: Transcribe audio files to text
### Text Processing
- **reverse_sentence**: Reverse text or sentences
- **python_code_parser**: Parse and analyze Python code
### Information Retrieval
- **web_search**: Search the web for information
- **web_content_extract**: Extract content from web pages
- **wikipedia_search**: Search Wikipedia for information
- **arvix_search**: Search academic papers on arXiv
### Utilities
- **convert_temperature**: Convert between temperature units
- **get_current_time_in_timezone**: Get current time in specific timezone
## Tool Usage Guidelines
- **Tool Evaluation Process**: Always survey ALL available tools before selecting one
- **Best Match Selection**: Choose the tool that best matches your specific need, not just any tool that could work
- **Multi-tool Operations**: Questions can require multiple tools in any sequence - plan your tool chain carefully
- **Sequential Processing**: Use outputs from one tool as inputs for another when necessary
- **File Processing Priority**: Always download and process files before attempting to answer questions about them
- **Mathematical Chains**: Combine mathematical operations as needed (e.g., add -> multiply -> percentage_calculator)
- **Information + Processing**: Combine search tools with processing tools (e.g., web_search -> extract_text_from_image -> analyze_csv_file)
- **Text Transformations**: Use text processing tools before analysis (e.g., reverse_sentence -> python_code_parser). In other words, first reverse the text when needed and then re-read the adjusted question.
- **Pattern Recognition**: Look for hidden patterns, instructions, or transformations within questions
## Response Format
After completing your analysis and using necessary tools, provide ONLY your final answer with no additional text, explanations, or formatting.
### Answer Formatting Rules:
- **Numbers**: Provide just the number without commas, units, or symbols (unless specifically requested)
- **Text**: Use minimal words, no articles, no abbreviations, write digits in plain text
- **Lists**: Comma-separated values following the above rules for each element type
- **Precision**: Be exact and concise - include only what is specifically asked for
- **No quotation marks**: Never wrap your answer in quotation marks or any other punctuation
### Critical Response Rule:
- Do NOT include "FINAL ANSWER:" or any other prefixes/labels
- Do NOT include explanations, reasoning, or additional text
- Do NOT use quotation marks around your answer
- Provide ONLY the answer itself - nothing else, keep it as short as possible and stick to the question.
## Process Flow
1. **Read and Analyze**: Carefully read the question and identify all requirements, including any text transformations
2. **Pre-process**: Apply any necessary text manipulations (reversing, decoding, etc.) to reveal the actual question
3. **Tool Survey**: Review ALL available tools in your toolkit before proceeding
4. **Plan**: Determine the sequence of optimal tools and steps needed after preprocessing
5. **Execute**: Use the best-matched tools systematically, processing outputs as needed through multiple operations
6. **Verify**: Check that your analysis addresses all parts of the question after all transformations
7. **Answer**: Provide only the raw answer with no formatting, labels, or additional text
## Important Notes
- Some questions may appear simple but require multiple tools or steps
- **Questions may contain hidden instructions that need text processing to reveal** (use reverse_sentence first)
- **Various tools are available** - evaluate ALL options to find the best match for each step
- **Multi-tool solutions are common** - expect to use 2-5 tools per complex question
- **Tool order is flexible** - arrange tools in the most logical sequence for your specific problem
- Always prioritize accuracy over speed
- If a question has multiple parts, ensure all parts are addressed with appropriate tools
- **Don't use the first tool that seems relevant** - use the BEST tool for each specific task
- Process any mentioned files, attachments, or external resources with download_file first
- **Be prepared to perform complex multi-step operations** across all tool categories
- Think through the problem systematically but provide only the final answer
Remember: Your goal is to provide accurate, precise answers to complex questions using the full range of available tools and capabilities. Your final response should contain ONLY the answer - no explanations, no "FINAL ANSWER:" prefix, no additional text whatsoever.
"""
# System message
sys_msg = SystemMessage(content=system_prompt)
def build_graph():
"""Build the graph"""
# First create the HuggingFaceEndpoint
llm_endpoint = HuggingFaceEndpoint(
repo_id="Qwen/Qwen2.5-14B-Instruct",
# repo_id="HuggingFaceH4/mistral-7b-anthropic", # wrong id?
# repo_id="Qwen/Qwen2.5-Coder-32B-Instruct", # this one is poor
# repo_id="meta-llama/Llama-3.1-8B", # other credential
huggingfacehub_api_token=HUGGINGFACEHUB_API_TOKEN,
temperature=0.1, # Maximum determinism
max_new_tokens=512, # Even more restrictive with 128
timeout=90, # Moderate timeout
do_sample=False, # Completely deterministic
)
# Then wrap it with ChatHuggingFace to get chat model functionality
llm = ChatHuggingFace(llm=llm_endpoint)
# Bind tools to LLM
llm_with_tools = llm.bind_tools(tools)
def assistant(state: MessagesState):
messages_with_system_prompt = [sys_msg] + state["messages"]
llm_response = llm_with_tools.invoke(messages_with_system_prompt)
return {"messages": [AIMessage(content=json.dumps(llm_response.content, ensure_ascii=False))]}
# --- Graph Definition ---
builder = StateGraph(MessagesState)
builder.add_node("assistant", assistant)
builder.add_node("tools", ToolNode(tools))
builder.add_edge(START, "assistant")
builder.add_conditional_edges("assistant", tools_condition)
builder.add_edge("tools", "assistant")
# Compile graph
return builder.compile()
# test
if __name__ == "__main__":
question = "What is 2 + 2?"
# Build the graph
graph = build_graph()
# Run the graph
messages = [HumanMessage(content=question)]
# The initial state for the graph
initial_state = {"messages": messages, "task_id": "test123"}
# Invoke the graph stream to see the steps
for s in graph.stream(initial_state, stream_mode="values"):
message = s["messages"][-1]
if isinstance(message, ToolMessage):
print("---RETRIEVED CONTEXT---")
print(message.content)
print("-----------------------")
else:
output = message.content # This is a string
print(f"Raw output: {output}")
try:
parsed = json.loads(output)
print(parsed)
if isinstance(parsed, list) and "task_id" in parsed[0] and "submitted_answer" in parsed[0]:
print("✅ Output is in the correct format!")
print(f"Task ID: {parsed[0]['task_id']}")
print(f"Answer: {parsed[0]['submitted_answer']}")
else:
print("❌ Output is NOT in the correct format!")
except Exception as e:
print("❌ Output is NOT in the correct format!", e)