import logging from yuxi.channel.extensions.slack.outbound import SlackOutbound from yuxi.channel.protocols import MessageActionCapability, AgentToolParam logger = logging.getLogger(__name__) _SUPPORTED_ACTIONS = frozenset({"send", "edit", "unsend", "react", "pin", "member_info"}) class SlackActions: def __init__(self): self._outbound = SlackOutbound() def get_message_actions(self) -> list[MessageActionCapability]: return [ MessageActionCapability( action="send", description="Send a message to a Slack channel or user", parameters=[ AgentToolParam(name="target_id", type="string", description="Channel ID or user ID", required=True), AgentToolParam(name="content", type="string", description="Message text to send", required=True), ], ), MessageActionCapability( action="edit", description="Edit a previously sent message", parameters=[ AgentToolParam(name="target_id", type="string", description="Channel ID", required=True), AgentToolParam( name="message_id", type="string", description="Message timestamp (ts)", required=True ), AgentToolParam(name="content", type="string", description="Updated message text", required=True), ], ), MessageActionCapability( action="unsend", description="Delete a previously sent message", parameters=[ AgentToolParam(name="target_id", type="string", description="Channel ID", required=True), AgentToolParam( name="message_id", type="string", description="Message timestamp (ts)", required=True ), ], ), MessageActionCapability( action="react", description="Add an emoji reaction to a message", parameters=[ AgentToolParam(name="target_id", type="string", description="Channel ID", required=True), AgentToolParam( name="message_id", type="string", description="Message timestamp (ts)", required=True ), AgentToolParam(name="emoji", type="string", description="Emoji name without colons", required=True), ], ), MessageActionCapability( action="pin", description="Pin a message to a channel", parameters=[ AgentToolParam(name="target_id", type="string", description="Channel ID", required=True), AgentToolParam( name="message_id", type="string", description="Message timestamp (ts)", required=True ), ], ), MessageActionCapability( action="member_info", description="Get information about a Slack user", parameters=[ AgentToolParam(name="target_id", type="string", description="User ID", required=True), ], ), ] async def execute_message_action(self, action: str, params: dict, context: dict) -> dict: account_id = context.get("account_id") try: match action: case "send": await self._outbound.send_text(params["target_id"], params["content"], account_id=account_id) return {"success": True, "result": None, "error": None} case "edit": result = await self._outbound.edit_message( params["target_id"], params["message_id"], params["content"], account_id=account_id, ) return {"success": True, "result": {"ts": result}, "error": None} case "unsend": await self._outbound.delete_message( params["target_id"], params["message_id"], account_id=account_id ) return {"success": True, "result": None, "error": None} case "react": await self._outbound.send_reaction( params["target_id"], params["message_id"], params["emoji"], account_id=account_id, ) return {"success": True, "result": None, "error": None} case "pin": await self._outbound.pin_message(params["target_id"], params["message_id"], account_id=account_id) return {"success": True, "result": None, "error": None} case "member_info": client, _account = await self._outbound._get_client(account_id) result = await client.users_info(user=params["target_id"]) return {"success": True, "result": result.data, "error": None} case _: return {"success": False, "result": None, "error": f"Unsupported action: {action}"} except Exception as e: logger.exception("Slack action '%s' failed", action) return {"success": False, "result": None, "error": str(e)} def supports_action(self, action: str) -> bool: return action in _SUPPORTED_ACTIONS def resolve_execution_mode(self, action: str) -> str: return "direct" def requires_trusted_requester_sender(self, action: str, tool_context=None) -> bool: return action in ("unsend", "pin")