mejorado bot de telegram

This commit is contained in:
2025-11-06 02:21:42 +01:00
parent b351e56614
commit 5d48cd4130
+76 -26
View File
@@ -2,12 +2,15 @@
from __future__ import annotations
import asyncio
import html
import os
import json
from contextlib import suppress
from typing import Any, Dict, List, Optional
from typing import Any, Dict, List, Optional, Set
import requests
from agno.agent.agent import RunOutput
from agno.run.agent import ToolCallStartedEvent
from dotenv import load_dotenv
from agentes import DEFAULT_AGENT_NAME, create_agent
@@ -51,11 +54,16 @@ class TelegramKanBot:
self.agent = None
self.context: Dict[str, Any] = {}
self.mcp_tool_names: Set[str] = set()
async def setup_agent(self) -> None:
agent, context = await create_agent(self.logger, agent=self.agent_key)
self.agent = agent
self.context = context
server_tool_map = context.get("server_tool_map") or {}
self.mcp_tool_names = {
tool_name for tools in server_tool_map.values() for tool_name in (tools or [])
}
self.logger.info(
"🤖 Agente Kan para Telegram listo",
add_fields={
@@ -186,8 +194,49 @@ class TelegramKanBot:
},
)
typing_task = asyncio.create_task(self._typing_indicator(chat_id))
notified_tool_calls: Set[str] = set()
response: Optional[RunOutput] = None
try:
response = await self.agent.arun(text)
run_result = await self.agent.arun(
text,
stream=True,
stream_events=True,
yield_run_response=True,
)
if isinstance(run_result, RunOutput):
response = run_result
else:
async for event in run_result:
if isinstance(event, RunOutput):
response = event
elif isinstance(event, ToolCallStartedEvent):
await self._maybe_notify_tool_execution(chat_id, event, notified_tool_calls)
if response is None:
raise RuntimeError("El agente no devolvió respuesta.")
content = (response.content or "(respuesta vacía)").strip()
if not content:
content = "(respuesta vacía)"
await self._send_message(chat_id, content)
if response.metrics:
self.logger.info(
"📊 Métricas de ejecución",
add_fields={
"agent_call": {"action": "agent_run_metrics"},
"agent_response": {
"status": "completed",
"metrics": {
"input_tokens": response.metrics.input_tokens,
"output_tokens": response.metrics.output_tokens,
"total_tokens": response.metrics.total_tokens,
"duration_seconds": response.metrics.duration,
},
},
},
)
except Exception as error: # pragma: no cover - manejo defensivo
self.logger.exception(
error,
@@ -203,32 +252,11 @@ class TelegramKanBot:
with suppress(asyncio.CancelledError):
await typing_task
content = (response.content or "(respuesta vacía)").strip()
if not content:
content = "(respuesta vacía)"
await self._send_message(chat_id, content)
if response.metrics:
self.logger.info(
"📊 Métricas de ejecución",
add_fields={
"agent_call": {"action": "agent_run_metrics"},
"agent_response": {
"status": "completed",
"metrics": {
"input_tokens": response.metrics.input_tokens,
"output_tokens": response.metrics.output_tokens,
"total_tokens": response.metrics.total_tokens,
"duration_seconds": response.metrics.duration,
},
},
},
)
async def _send_message(self, chat_id: int, text: str) -> None:
async def _send_message(self, chat_id: int, text: str, *, parse_mode: Optional[str] = None) -> None:
for chunk in self._chunk_text(text):
payload = {"chat_id": chat_id, "text": chunk}
if parse_mode:
payload["parse_mode"] = parse_mode
try:
response = await asyncio.to_thread(
self.session.post,
@@ -255,6 +283,28 @@ class TelegramKanBot:
},
)
async def _maybe_notify_tool_execution(
self,
chat_id: int,
event: ToolCallStartedEvent,
notified_tool_calls: Set[str],
) -> None:
if not self.mcp_tool_names:
return
tool = getattr(event, "tool", None)
if not tool or not tool.tool_name:
return
tool_identifier = tool.tool_call_id or f"{tool.tool_name}:{len(notified_tool_calls)}"
if tool_identifier in notified_tool_calls:
return
if tool.tool_name not in self.mcp_tool_names:
return
notified_tool_calls.add(tool_identifier)
escaped_name = html.escape(tool.tool_name)
await self._send_message(chat_id, f"<i>Ejecutado {escaped_name}</i>", parse_mode="HTML")
async def _typing_indicator(self, chat_id: int) -> None:
try:
while True: