6161 "MessageInteraction" ,
6262 "InteractionMetadata" ,
6363 "AuthorizingIntegrationOwners" ,
64+ "InteractionCallback" ,
6465)
6566
6667if TYPE_CHECKING :
8384 from .state import ConnectionState
8485 from .threads import Thread
8586 from .types .interactions import Interaction as InteractionPayload
86- from .types .interactions import InteractionData
87+ from .types .interactions import InteractionCallback as InteractionCallbackPayload
88+ from .types .interactions import InteractionCallbackResponse , InteractionData
8789 from .types .interactions import InteractionMetadata as InteractionMetadataPayload
8890 from .types .interactions import MessageInteraction as MessageInteractionPayload
8991 from .ui .modal import Modal
@@ -153,6 +155,11 @@ class Interaction:
153155 The context in which this command was executed.
154156
155157 .. versionadded:: 2.6
158+ callback: Optional[:class:`InteractionCallback`]
159+ The callback of the interaction. Contains information about the status of the interaction response.
160+ Will be `None` until the interaction is responded to.
161+
162+ .. versionadded:: 2.7
156163 command: Optional[:class:`ApplicationCommand`]
157164 The command that this interaction belongs to.
158165
@@ -189,6 +196,7 @@ class Interaction:
189196 "entitlements" ,
190197 "context" ,
191198 "authorizing_integration_owners" ,
199+ "callback" ,
192200 "command" ,
193201 "view" ,
194202 "modal" ,
@@ -213,6 +221,7 @@ def __init__(self, *, data: InteractionPayload, state: ConnectionState):
213221 self ._state : ConnectionState = state
214222 self ._session : ClientSession = state .http ._HTTPClient__session
215223 self ._original_response : InteractionMessage | None = None
224+ self .callback : InteractionCallback | None = None
216225 self ._from_data (data )
217226
218227 def _from_data (self , data : InteractionPayload ):
@@ -468,7 +477,9 @@ async def original_response(self) -> InteractionMessage:
468477 # TODO: fix later to not raise?
469478 channel = self .channel
470479 if channel is None :
471- raise ClientException ("Channel for message could not be resolved" )
480+ raise ClientException (
481+ "Channel for message could not be resolved. Please open a issue on GitHub if you encounter this error."
482+ )
472483
473484 adapter = async_context .get ()
474485 http = self ._state .http
@@ -860,18 +871,21 @@ async def defer(self, *, ephemeral: bool = False, invisible: bool = True) -> Non
860871 if defer_type :
861872 adapter = async_context .get ()
862873 http = parent ._state .http
863- await self ._locked_response (
864- adapter .create_interaction_response (
865- parent .id ,
866- parent .token ,
867- session = parent ._session ,
868- type = defer_type ,
869- data = data ,
870- proxy = http .proxy ,
871- proxy_auth = http .proxy_auth ,
874+ callback_response : InteractionCallbackResponse = (
875+ await self ._locked_response (
876+ adapter .create_interaction_response (
877+ parent .id ,
878+ parent .token ,
879+ session = parent ._session ,
880+ type = defer_type ,
881+ data = data ,
882+ proxy = http .proxy ,
883+ proxy_auth = http .proxy_auth ,
884+ )
872885 )
873886 )
874887 self ._responded = True
888+ await self ._process_callback_response (callback_response )
875889
876890 async def pong (self ) -> None :
877891 """|coro|
@@ -894,17 +908,36 @@ async def pong(self) -> None:
894908 if parent .type is InteractionType .ping :
895909 adapter = async_context .get ()
896910 http = parent ._state .http
897- await self ._locked_response (
898- adapter .create_interaction_response (
899- parent .id ,
900- parent .token ,
901- session = parent ._session ,
902- proxy = http .proxy ,
903- proxy_auth = http .proxy_auth ,
904- type = InteractionResponseType .pong .value ,
911+ callback_response : InteractionCallbackResponse = (
912+ await self ._locked_response (
913+ adapter .create_interaction_response (
914+ parent .id ,
915+ parent .token ,
916+ session = parent ._session ,
917+ proxy = http .proxy ,
918+ proxy_auth = http .proxy_auth ,
919+ type = InteractionResponseType .pong .value ,
920+ )
905921 )
906922 )
907923 self ._responded = True
924+ await self ._process_callback_response (callback_response )
925+
926+ async def _process_callback_response (
927+ self , callback_response : InteractionCallbackResponse
928+ ):
929+ if callback_response .get ("resource" , {}).get ("message" ):
930+ # TODO: fix later to not raise?
931+ channel = self ._parent .channel
932+ if channel is None :
933+ raise ClientException (
934+ "Channel for message could not be resolved. Please open a issue on GitHub if you encounter this error."
935+ )
936+ state = _InteractionMessageState (self ._parent , self ._parent ._state )
937+ message = InteractionMessage (state = state , channel = channel , data = callback_response ["resource" ]["message" ]) # type: ignore
938+ self ._parent ._original_response = message
939+
940+ self ._parent .callback = InteractionCallback (callback_response ["interaction" ])
908941
909942 async def send_message (
910943 self ,
@@ -1048,16 +1081,18 @@ async def send_message(
10481081 adapter = async_context .get ()
10491082 http = parent ._state .http
10501083 try :
1051- await self ._locked_response (
1052- adapter .create_interaction_response (
1053- parent .id ,
1054- parent .token ,
1055- session = parent ._session ,
1056- type = InteractionResponseType .channel_message .value ,
1057- proxy = http .proxy ,
1058- proxy_auth = http .proxy_auth ,
1059- data = payload ,
1060- files = files ,
1084+ callback_response : InteractionCallbackResponse = (
1085+ await self ._locked_response (
1086+ adapter .create_interaction_response (
1087+ parent .id ,
1088+ parent .token ,
1089+ session = parent ._session ,
1090+ type = InteractionResponseType .channel_message .value ,
1091+ proxy = http .proxy ,
1092+ proxy_auth = http .proxy_auth ,
1093+ data = payload ,
1094+ files = files ,
1095+ )
10611096 )
10621097 )
10631098 finally :
@@ -1074,6 +1109,7 @@ async def send_message(
10741109 self ._parent ._state .store_view (view )
10751110
10761111 self ._responded = True
1112+ await self ._process_callback_response (callback_response )
10771113 if delete_after is not None :
10781114 await self ._parent .delete_original_response (delay = delete_after )
10791115 return self ._parent
@@ -1213,16 +1249,18 @@ async def edit_message(
12131249 adapter = async_context .get ()
12141250 http = parent ._state .http
12151251 try :
1216- await self ._locked_response (
1217- adapter .create_interaction_response (
1218- parent .id ,
1219- parent .token ,
1220- session = parent ._session ,
1221- type = InteractionResponseType .message_update .value ,
1222- proxy = http .proxy ,
1223- proxy_auth = http .proxy_auth ,
1224- data = payload ,
1225- files = files ,
1252+ callback_response : InteractionCallbackResponse = (
1253+ await self ._locked_response (
1254+ adapter .create_interaction_response (
1255+ parent .id ,
1256+ parent .token ,
1257+ session = parent ._session ,
1258+ type = InteractionResponseType .message_update .value ,
1259+ proxy = http .proxy ,
1260+ proxy_auth = http .proxy_auth ,
1261+ data = payload ,
1262+ files = files ,
1263+ )
12261264 )
12271265 )
12281266 finally :
@@ -1235,6 +1273,7 @@ async def edit_message(
12351273 state .store_view (view , message_id )
12361274
12371275 self ._responded = True
1276+ await self ._process_callback_response (callback_response )
12381277 if delete_after is not None :
12391278 await self ._parent .delete_original_response (delay = delete_after )
12401279
@@ -1270,7 +1309,7 @@ async def send_autocomplete_result(
12701309
12711310 adapter = async_context .get ()
12721311 http = parent ._state .http
1273- await self ._locked_response (
1312+ callback_response : InteractionCallbackResponse = await self ._locked_response (
12741313 adapter .create_interaction_response (
12751314 parent .id ,
12761315 parent .token ,
@@ -1283,6 +1322,7 @@ async def send_autocomplete_result(
12831322 )
12841323
12851324 self ._responded = True
1325+ await self ._process_callback_response (callback_response )
12861326
12871327 async def send_modal (self , modal : Modal ) -> Interaction :
12881328 """|coro|
@@ -1309,7 +1349,7 @@ async def send_modal(self, modal: Modal) -> Interaction:
13091349 payload = modal .to_dict ()
13101350 adapter = async_context .get ()
13111351 http = parent ._state .http
1312- await self ._locked_response (
1352+ callback_response : InteractionCallbackResponse = await self ._locked_response (
13131353 adapter .create_interaction_response (
13141354 parent .id ,
13151355 parent .token ,
@@ -1321,6 +1361,7 @@ async def send_modal(self, modal: Modal) -> Interaction:
13211361 )
13221362 )
13231363 self ._responded = True
1364+ await self ._process_callback_response (callback_response )
13241365 self ._parent ._state .store_modal (modal , self ._parent .user .id )
13251366 return self ._parent
13261367
@@ -1348,7 +1389,7 @@ async def premium_required(self) -> Interaction:
13481389
13491390 adapter = async_context .get ()
13501391 http = parent ._state .http
1351- await self ._locked_response (
1392+ callback_response : InteractionCallbackResponse = await self ._locked_response (
13521393 adapter .create_interaction_response (
13531394 parent .id ,
13541395 parent .token ,
@@ -1359,9 +1400,10 @@ async def premium_required(self) -> Interaction:
13591400 )
13601401 )
13611402 self ._responded = True
1403+ await self ._process_callback_response (callback_response )
13621404 return self ._parent
13631405
1364- async def _locked_response (self , coro : Coroutine [Any , Any , Any ]) -> None :
1406+ async def _locked_response (self , coro : Coroutine [Any , Any , Any ]) -> Any :
13651407 """|coro|
13661408
13671409 Wraps a response and makes sure that it's locked while executing.
@@ -1371,16 +1413,24 @@ async def _locked_response(self, coro: Coroutine[Any, Any, Any]) -> None:
13711413 coro: Coroutine[Any]
13721414 The coroutine to wrap.
13731415
1416+ Returns
1417+ -------
1418+ Any
1419+ The result of the coroutine.
1420+
13741421 Raises
13751422 ------
13761423 InteractionResponded
13771424 This interaction has already been responded to before.
1425+
1426+ .. versionchanged:: 2.7
1427+ Return the result of the coroutine
13781428 """
13791429 async with self ._response_lock :
13801430 if self .is_done ():
13811431 coro .close () # cleanup un-awaited coroutine
13821432 raise InteractionResponded (self ._parent )
1383- await coro
1433+ return await coro
13841434
13851435
13861436class _InteractionMessageState :
@@ -1704,3 +1754,36 @@ def guild(self) -> Guild | None:
17041754 if not self .guild_id :
17051755 return None
17061756 return self ._state ._get_guild (self .guild_id )
1757+
1758+
1759+ class InteractionCallback :
1760+ """Information about the status of the interaction response.
1761+
1762+ .. versionadded:: 2.7
1763+ """
1764+
1765+ def __init__ (self , data : InteractionCallbackPayload ):
1766+ self ._response_message_loading : bool = data .get (
1767+ "response_message_loading" , False
1768+ )
1769+ self ._response_message_ephemeral : bool = data .get (
1770+ "response_message_ephemeral" , False
1771+ )
1772+
1773+ def __repr__ (self ):
1774+ return (
1775+ f"<InteractionCallback "
1776+ f"_response_message_loading={ self ._response_message_loading } "
1777+ f"_response_message_ephemeral={ self ._response_message_ephemeral } >"
1778+ )
1779+
1780+ def is_loading (self ) -> bool :
1781+ """Indicates whether the response message is in a loading state."""
1782+ return self ._response_message_loading
1783+
1784+ def is_ephemeral (self ) -> bool :
1785+ """Indicates whether the response message is ephemeral.
1786+
1787+ This might be useful for determining if the message was forced to be ephemeral.
1788+ """
1789+ return self ._response_message_ephemeral
0 commit comments