mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
refactor(gateway): shared reaction-ack policy in base adapter
- base.on_processing_complete implements the opt-in remove-ack/add-outcome flow driven by _OK_EMOJI/_FAIL_EMOJI class attrs and the _add_reaction(chat_id, message_id, emoji)/_remove_reaction(chat_id, message_id) primitive shape; default stays a no-op. - photon drops its override (exact behavioral match). - slack/discord/feishu/matrix/telegram/google_chat keep overrides: divergent primitive signatures (team_id routing, raw message objects, reaction-id handles, replace-semantics setMessageReaction) or extra state protocols.
This commit is contained in:
parent
58400a6793
commit
4fe5410d57
2 changed files with 49 additions and 22 deletions
|
|
@ -4793,11 +4793,52 @@ class BasePlatformAdapter(ABC):
|
|||
# Subclasses override these to react to message processing events
|
||||
# (e.g. Discord adds 👀/✅/❌ reactions).
|
||||
|
||||
# Opt-in emoji set for the shared reaction-ack flow in
|
||||
# ``on_processing_complete``. Adapters whose reaction primitives follow
|
||||
# the ``_add_reaction(chat_id, message_id, emoji)`` /
|
||||
# ``_remove_reaction(chat_id, message_id)`` shape can set these class
|
||||
# attributes instead of overriding the hook. Left as ``None`` the hook
|
||||
# stays a no-op (historical default).
|
||||
_ACK_EMOJI: Optional[str] = None
|
||||
_OK_EMOJI: Optional[str] = None
|
||||
_FAIL_EMOJI: Optional[str] = None
|
||||
|
||||
async def on_processing_start(self, event: MessageEvent) -> None:
|
||||
"""Hook called when background processing begins."""
|
||||
|
||||
async def on_processing_complete(self, event: MessageEvent, outcome: ProcessingOutcome) -> None:
|
||||
"""Hook called when background processing completes."""
|
||||
"""Hook called when background processing completes.
|
||||
|
||||
Default: shared reaction-ack flow — swap the in-progress reaction for
|
||||
a final success/failure reaction. Runs only when the adapter opts in
|
||||
by setting ``_OK_EMOJI`` / ``_FAIL_EMOJI`` class attributes AND
|
||||
defines ``_add_reaction`` / ``_remove_reaction`` primitives taking
|
||||
``(chat_id, message_id[, emoji])``. Otherwise this is a no-op, as it
|
||||
always was. Remove-then-add rather than a bare replace: deterministic
|
||||
whether the platform replaces a sender's previous reaction or stacks
|
||||
them. CANCELLED outcomes leave the message unreacted.
|
||||
"""
|
||||
if self._OK_EMOJI is None and self._FAIL_EMOJI is None:
|
||||
return
|
||||
add: Any = getattr(self, "_add_reaction", None)
|
||||
remove: Any = getattr(self, "_remove_reaction", None)
|
||||
if not callable(add) or not callable(remove):
|
||||
return
|
||||
enabled = getattr(self, "_reactions_enabled", None)
|
||||
if callable(enabled) and not enabled():
|
||||
return
|
||||
chat_id = getattr(event.source, "chat_id", None)
|
||||
message_id = getattr(event, "message_id", None)
|
||||
if not chat_id or not message_id:
|
||||
return
|
||||
await remove(chat_id, message_id)
|
||||
if outcome == ProcessingOutcome.SUCCESS:
|
||||
if self._OK_EMOJI:
|
||||
await add(chat_id, message_id, self._OK_EMOJI)
|
||||
elif outcome == ProcessingOutcome.FAILURE:
|
||||
if self._FAIL_EMOJI:
|
||||
await add(chat_id, message_id, self._FAIL_EMOJI)
|
||||
# CANCELLED: leave the message unreacted.
|
||||
|
||||
async def _run_processing_hook(self, hook_name: str, *args: Any, **kwargs: Any) -> None:
|
||||
"""Run a lifecycle hook without letting failures break message flow."""
|
||||
|
|
|
|||
|
|
@ -2295,27 +2295,13 @@ class PhotonAdapter(BasePlatformAdapter):
|
|||
if chat_id and message_id:
|
||||
await self._add_reaction(chat_id, message_id, "\U0001f440")
|
||||
|
||||
async def on_processing_complete(
|
||||
self, event: MessageEvent, outcome: ProcessingOutcome
|
||||
) -> None:
|
||||
"""Swap the 👀 progress tapback for a 👍/👎 result.
|
||||
|
||||
Remove-then-add rather than a bare replace: deterministic whether the
|
||||
platform replaces a sender's previous tapback or stacks them, and it
|
||||
keeps the sidecar's reaction-handle slot coherent.
|
||||
"""
|
||||
if not self._reactions_enabled():
|
||||
return
|
||||
chat_id = getattr(event.source, "chat_id", None)
|
||||
message_id = getattr(event, "message_id", None)
|
||||
if not chat_id or not message_id:
|
||||
return
|
||||
await self._remove_reaction(chat_id, message_id)
|
||||
if outcome == ProcessingOutcome.SUCCESS:
|
||||
await self._add_reaction(chat_id, message_id, "\U0001f44d")
|
||||
elif outcome == ProcessingOutcome.FAILURE:
|
||||
await self._add_reaction(chat_id, message_id, "\U0001f44e")
|
||||
# CANCELLED: leave the message unreacted.
|
||||
# Shared reaction-ack flow (base.on_processing_complete): swap the 👀
|
||||
# progress tapback for a 👍/👎 result. Remove-then-add rather than a bare
|
||||
# replace: deterministic whether the platform replaces a sender's previous
|
||||
# tapback or stacks them, and it keeps the sidecar's reaction-handle slot
|
||||
# coherent. CANCELLED: leave the message unreacted.
|
||||
_OK_EMOJI = "\U0001f44d"
|
||||
_FAIL_EMOJI = "\U0001f44e"
|
||||
|
||||
async def get_chat_info(self, chat_id: str) -> Dict[str, Any]:
|
||||
"""Return whatever we know about a Spectrum space id.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue