Spaces:
Running
Running
| """ | |
| Basic agent loop using the Anthropic Claude API. | |
| Receives user input, calls tools as needed, and returns results. | |
| """ | |
| import os | |
| import sys | |
| # Thêm thư mục gốc của dự án vào sys.path để hỗ trợ chạy file trực tiếp | |
| project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) | |
| if project_root not in sys.path: | |
| sys.path.append(project_root) | |
| import logging | |
| from typing import Any | |
| from langchain_core.messages import HumanMessage, AIMessage, ToolMessage, SystemMessage | |
| from datetime import datetime | |
| from src.llm import llm | |
| from src.config import DEFAULT_MODEL, LOG_LEVEL | |
| from src.prompts import AGENT_SYSTEM_PROMPT | |
| from src.tools import get_tool_schemas, execute_tool, get_langchain_tools | |
| logging.basicConfig(level=LOG_LEVEL, format="%(asctime)s [%(levelname)s] %(message)s") | |
| logger = logging.getLogger(__name__) | |
| def create_agent(): | |
| """Returns the LLM instance configured from src/llm.py.""" | |
| return llm | |
| def run_agent_loop(client: Any, user_input: str, max_turns: int = 10) -> str: | |
| """ | |
| Run the agent loop: send message -> receive response -> call tool -> repeat. | |
| """ | |
| # Dynamic Date Injection | |
| today = datetime.now() | |
| time_context = f"\n[CURRENT TIME CONTEXT]\nToday is {today.strftime('%A, %B %d, %Y')}.\n" | |
| messages = [ | |
| SystemMessage(content=AGENT_SYSTEM_PROMPT + time_context), | |
| HumanMessage(content=user_input) | |
| ] | |
| # Bind tools to the LLM | |
| lc_tools = get_langchain_tools() | |
| llm_with_tools = client.bind_tools(lc_tools) | |
| for turn in range(max_turns): | |
| logger.info(f"Turn {turn + 1}/{max_turns}") | |
| response = llm_with_tools.invoke(messages) | |
| messages.append(response) | |
| # If no tool calls, return the final response | |
| if not response.tool_calls: | |
| content = response.content | |
| if isinstance(content, str): | |
| return content | |
| if isinstance(content, list): | |
| return "".join(b.get("text", "") if isinstance(b, dict) else str(b) for b in content) | |
| return str(content) | |
| # Handle tool calls | |
| for tc in response.tool_calls: | |
| tool_name = tc["name"] | |
| logger.info(f"Calling tool: {tool_name}({tc['args']})") | |
| result = execute_tool(tool_name, tc["args"]) | |
| logger.info(f"Result: {str(result)[:200]}") | |
| messages.append(ToolMessage( | |
| content=str(result), | |
| tool_call_id=tc["id"], | |
| name=tool_name | |
| )) | |
| return "Agent reached the maximum number of processing turns." | |
| def main(): | |
| """Interactive loop - enter a prompt and receive results.""" | |
| client = create_agent() | |
| print("Agentic App (type 'quit' to exit)") | |
| print("-" * 50) | |
| while True: | |
| user_input = input("\nYou: ").strip() | |
| if not user_input or user_input.lower() in ("quit", "exit", "q"): | |
| print("Bye!") | |
| break | |
| try: | |
| response = run_agent_loop(client, user_input) | |
| print(f"\nAgent: {response}") | |
| except Exception as e: | |
| logger.error(f"Error: {e}") | |
| print(f"\nError: {e}") | |
| if __name__ == "__main__": | |
| main() | |