mejorado bot de telegram
This commit is contained in:
+76
-26
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user