Compare commits

..
1 Commits
Author SHA1 Message Date
Shivering Ocelot 279861bdb8 wip: responsiveness 2026-10-14 01:36:02 -05:00
+48
View File
@@ -249,6 +249,7 @@ class Channels:
})
self._trim(state["transcript"])
transcript = self._render(state["transcript"])
await self.mark_as_read(agent_id, chat_id)
await self._run_agent(agent_id, kind, chat_id, chat, sender_name, transcript)
async def _run_agent(self, agent_id, kind, chat_id, chat, sender_name, transcript):
@@ -274,6 +275,9 @@ class Channels:
f"Latest message from: {sender_name}",
])
# Signal presence for the lifetime of this run.
await self.set_online_status(agent_id, chat_id, online=True)
tool = ToolSpec(
name="send_message",
description="Send a text message back to this Telegram conversation.",
@@ -338,6 +342,13 @@ class Channels:
if len(text) > MAX_MESSAGE_LENGTH:
text = text[:MAX_MESSAGE_LENGTH]
# Typing indicator immediately before the message so the user sees
# the three-dot animation right as the reply is ready.
try:
await self._api(token, "sendAction", {"chat_id": chat_id, "action": "typing"})
except Exception as e:
print(f"[channel] sendAction typing failed for agent {agent_id}: {e}")
try:
await self._api(token, "sendMessage", {"chat_id": chat_id, "text": text})
return "ok"
@@ -345,6 +356,43 @@ class Channels:
print(f"[channel] sendMessage failed for agent {agent_id}: {e}")
return f"error: {e}"
async def send_typing(self, agent_id, chat_id, typing=True):
"""Send a typing action indicator to the chat.
Telegram exposes this via ``sendAction`` with ``typing`` (start) or
``cancel`` (stop). Failures are swallowed: an indicator is cosmetic
and must never break a run.
"""
binding = await self.get_binding(agent_id)
if binding is None:
return
token = (binding.value or {}).get("token")
if not token:
return
action = "typing" if typing else "cancel"
try:
await self._api(token, "sendAction", {"chat_id": chat_id, "action": action})
except Exception as e:
print(f"[channel] sendAction failed: {e}")
async def mark_as_read(self, agent_id, chat_id):
"""Mark an inbound message as read.
Telegram bots have no native read receipt; acceptance is already
handled by :meth:`accept_update`. This stays an explicit hook on the
inbound path so a provider that does support receipts can be wired in
here later.
"""
pass
async def set_online_status(self, agent_id, chat_id, online=True):
"""Signal presence for the conversation.
A single ``typing`` action marks the run as online; ``cancel`` clears
it. Delegates to :meth:`send_typing`.
"""
await self.send_typing(agent_id, chat_id, typing=online)
# --- In-memory transcript ---
def _state(self, agent_id, chat_id):