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)