feat: Add NaliiaTools

This commit is contained in:
2026-02-16 16:35:15 -05:00
parent 63758f5f9c
commit 66fe0a2a13
7 changed files with 100 additions and 34 deletions

View File

@@ -1,5 +1,6 @@
from langgraph.graph import StateGraph, START, END
from langchain_core.messages import SystemMessage, ToolMessage, BaseMessage
import logging
from typing import Literal, Callable, Any
from .schemas import MessagesState
from dataclasses import dataclass
@@ -38,10 +39,9 @@ class Agent:
- Si es None: sin herramientas
- Si es list: lista de herramientas
"""
self._model = model
self._config = config or AgentConfig()
# Normalizar tools: usar la lista proporcionada o lista vacía
self._tools = tools or []
self._tools_by_name: dict[str, Any] = {
@@ -49,7 +49,6 @@ class Agent:
}
self._compiled_agent = self._compile_agent()
# Hooks para testing (monkey-patching friendly)
self._pre_llm_hook: Callable | None = None
self._post_tool_hook: Callable | None = None
@@ -92,26 +91,28 @@ class Agent:
def set_pre_llm_hook(self, hook: Callable[[dict], None]):
"""Registra hook pre-llm para testing."""
self._pre_llm_hook = hook
def set_post_tool_hook(self, hook: Callable[[dict, Any], None]):
"""Registra hook post-tool para testing."""
self._post_tool_hook = hook
def _compile_agent(self):
"""Compila el grafo una sola vez."""
agent = self._build_agent()
return agent.compile()
def _build_agent(self) -> StateGraph:
"""Construye el grafo de estado completo."""
agent_builder = StateGraph(MessagesState)
# Nodos
agent_builder.add_node("llm_call", self._llm_call_node)
agent_builder.add_node("tool_node", self._tool_node)
# Flujo
agent_builder.add_edge(START, "llm_call")
agent_builder.add_conditional_edges(
"llm_call",
@@ -125,8 +126,6 @@ class Agent:
return agent_builder
# ============ Nodos del Grafo ============
def _llm_call_node(self, state: MessagesState) -> dict:
"""
Nodo LLM: Decide siguiente acción o responde.
@@ -143,6 +142,7 @@ class Agent:
] + state["messages"]
model_with_tools = self._model.bind_tools(self._tools)
response = model_with_tools.invoke(messages)
current_calls = state.get("llm_calls", 0)
@@ -185,29 +185,30 @@ class Agent:
Ejecuta una herramienta individual con manejo de errores.
"""
tool_name = tool_call.get("name")
tool_id = tool_call.get("id", "unknown")
tool_id = tool_call.get("id")
tool_args = tool_call.get("args", {})
if tool_name not in self._tools_by_name:
return ToolMessage(
content=f"Error: Tool '{tool_name}' not found",
tool_call_id=tool_id,
status="error"
name=tool_name,
)
try:
tool = self._tools_by_name[tool_name]
observation = tool.invoke(tool_args)
return ToolMessage(
content=str(observation),
tool_call_id=tool_id,
status="success"
)
name=tool_name)
except Exception as e:
return ToolMessage(
content=f"Error executing tool: {str(e)}",
tool_call_id=tool_id,
status="error"
name=tool_name,
)
def _should_continue(