feat: add edit_message + streaming support to Zulip adapter

Implements edit_message() using Zulip's PATCH /api/v1/messages/{id} API.
Enables the Hermes GatewayStreamConsumer to progressively update Zulip
messages during agent generation, giving users real-time visibility into
agent thinking via progressive edits.

Adds _api_patch() helper for PATCH HTTP method.
This commit is contained in:
Abiba
2026-07-13 06:49:43 +00:00
committed by Abiba (pi)
parent e1b76376b1
commit bfc6e1877d
+33
View File
@@ -203,6 +203,22 @@ class ZulipAdapter(BasePlatformAdapter):
logger.error("Zulip POST %s network error: %s", path, exc) logger.error("Zulip POST %s network error: %s", path, exc)
return {"result": "error", "msg": str(exc)} return {"result": "error", "msg": str(exc)}
async def _api_patch(self, path: str, payload: Dict[str, Any]) -> Dict[str, Any]:
import aiohttp
url = f"{self._site}/api/v1/{path.lstrip('/')}"
try:
async with self._session.patch(
url, data=payload, auth=self._auth(),
timeout=aiohttp.ClientTimeout(total=15),
) as resp:
data = await resp.json()
if resp.status >= 400:
logger.debug("Zulip PATCH %s -> %s: %s", path, resp.status, str(data)[:200])
return data
except (aiohttp.ClientError, asyncio.TimeoutError) as exc:
logger.debug("Zulip PATCH %s network error: %s", path, exc)
return {"result": "error", "msg": str(exc)}
async def _api_delete(self, path: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: async def _api_delete(self, path: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
import aiohttp import aiohttp
url = f"{self._site}/api/v1/{path.lstrip('/')}" url = f"{self._site}/api/v1/{path.lstrip('/')}"
@@ -326,6 +342,23 @@ class ZulipAdapter(BasePlatformAdapter):
return SendResult(success=True, message_id=str(last_id) if last_id else None) return SendResult(success=True, message_id=str(last_id) if last_id else None)
async def edit_message(
self,
chat_id: str,
message_id: str,
content: str,
**kwargs,
) -> SendResult:
"""Edit a previously-sent message. Used by the gateway stream consumer
for progressive message updates during agent streaming."""
formatted = self.format_message(content)
data = await self._api_patch(f"messages/{message_id}", {"content": formatted})
if data.get("result") != "success":
msg = str(data.get("msg", "edit failed"))
logger.debug("Zulip edit_message(%s) -> %s", message_id, msg)
return SendResult(success=False, error=msg)
return SendResult(success=True, message_id=message_id)
async def get_chat_info(self, chat_id: str) -> Dict[str, Any]: async def get_chat_info(self, chat_id: str) -> Dict[str, Any]:
kind, to, topic = _parse_target(chat_id, self._default_topic) kind, to, topic = _parse_target(chat_id, self._default_topic)
if kind == "direct": if kind == "direct":