6262 "MessageInteraction" ,
6363 "InteractionMetadata" ,
6464 "AuthorizingIntegrationOwners" ,
65+ "InteractionCallback" ,
6566)
6667
6768if TYPE_CHECKING :
8485 from .state import ConnectionState
8586 from .threads import Thread
8687 from .types .interactions import Interaction as InteractionPayload
87- from .types .interactions import InteractionData
88+ from .types .interactions import InteractionCallback as InteractionCallbackPayload
89+ from .types .interactions import InteractionCallbackResponse , InteractionData
8890 from .types .interactions import InteractionMetadata as InteractionMetadataPayload
8991 from .types .interactions import MessageInteraction as MessageInteractionPayload
9092 from .ui .modal import Modal
@@ -154,6 +156,11 @@ class Interaction:
154156 The context in which this command was executed.
155157
156158 .. versionadded:: 2.6
159+ callback: Optional[:class:`InteractionCallback`]
160+ The callback of the interaction. Contains information about the status of the interaction response.
161+ Will be `None` until the interaction is responded to.
162+
163+ .. versionadded:: 2.7
157164 command: Optional[:class:`ApplicationCommand`]
158165 The command that this interaction belongs to.
159166
@@ -190,6 +197,7 @@ class Interaction:
190197 "entitlements" ,
191198 "context" ,
192199 "authorizing_integration_owners" ,
200+ "callback" ,
193201 "command" ,
194202 "view" ,
195203 "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 ):
@@ -443,7 +452,9 @@ async def original_response(self) -> InteractionMessage:
443452 # TODO: fix later to not raise?
444453 channel = self .channel
445454 if channel is None :
446- raise ClientException ("Channel for message could not be resolved" )
455+ raise ClientException (
456+ "Channel for message could not be resolved. Please open a issue on GitHub if you encounter this error."
457+ )
447458
448459 adapter = async_context .get ()
449460 http = self ._state .http
@@ -828,18 +839,21 @@ async def defer(self, *, ephemeral: bool = False, invisible: bool = True) -> Non
828839 if defer_type :
829840 adapter = async_context .get ()
830841 http = parent ._state .http
831- await self ._locked_response (
832- adapter .create_interaction_response (
833- parent .id ,
834- parent .token ,
835- session = parent ._session ,
836- type = defer_type ,
837- data = data ,
838- proxy = http .proxy ,
839- proxy_auth = http .proxy_auth ,
842+ callback_response : InteractionCallbackResponse = (
843+ await self ._locked_response (
844+ adapter .create_interaction_response (
845+ parent .id ,
846+ parent .token ,
847+ session = parent ._session ,
848+ type = defer_type ,
849+ data = data ,
850+ proxy = http .proxy ,
851+ proxy_auth = http .proxy_auth ,
852+ )
840853 )
841854 )
842855 self ._responded = True
856+ await self ._process_callback_response (callback_response )
843857
844858 async def pong (self ) -> None :
845859 """|coro|
@@ -862,17 +876,36 @@ async def pong(self) -> None:
862876 if parent .type is InteractionType .ping :
863877 adapter = async_context .get ()
864878 http = parent ._state .http
865- await self ._locked_response (
866- adapter .create_interaction_response (
867- parent .id ,
868- parent .token ,
869- session = parent ._session ,
870- proxy = http .proxy ,
871- proxy_auth = http .proxy_auth ,
872- type = InteractionResponseType .pong .value ,
879+ callback_response : InteractionCallbackResponse = (
880+ await self ._locked_response (
881+ adapter .create_interaction_response (
882+ parent .id ,
883+ parent .token ,
884+ session = parent ._session ,
885+ proxy = http .proxy ,
886+ proxy_auth = http .proxy_auth ,
887+ type = InteractionResponseType .pong .value ,
888+ )
873889 )
874890 )
875891 self ._responded = True
892+ await self ._process_callback_response (callback_response )
893+
894+ async def _process_callback_response (
895+ self , callback_response : InteractionCallbackResponse
896+ ):
897+ if callback_response .get ("resource" , {}).get ("message" ):
898+ # TODO: fix later to not raise?
899+ channel = self ._parent .channel
900+ if channel is None :
901+ raise ClientException (
902+ "Channel for message could not be resolved. Please open a issue on GitHub if you encounter this error."
903+ )
904+ state = _InteractionMessageState (self ._parent , self ._parent ._state )
905+ message = InteractionMessage (state = state , channel = channel , data = callback_response ["resource" ]["message" ]) # type: ignore
906+ self ._parent ._original_response = message
907+
908+ self ._parent .callback = InteractionCallback (callback_response ["interaction" ])
876909
877910 async def send_message (
878911 self ,
@@ -1008,16 +1041,18 @@ async def send_message(
10081041 adapter = async_context .get ()
10091042 http = parent ._state .http
10101043 try :
1011- await self ._locked_response (
1012- adapter .create_interaction_response (
1013- parent .id ,
1014- parent .token ,
1015- session = parent ._session ,
1016- type = InteractionResponseType .channel_message .value ,
1017- proxy = http .proxy ,
1018- proxy_auth = http .proxy_auth ,
1019- data = payload ,
1020- files = files ,
1044+ callback_response : InteractionCallbackResponse = (
1045+ await self ._locked_response (
1046+ adapter .create_interaction_response (
1047+ parent .id ,
1048+ parent .token ,
1049+ session = parent ._session ,
1050+ type = InteractionResponseType .channel_message .value ,
1051+ proxy = http .proxy ,
1052+ proxy_auth = http .proxy_auth ,
1053+ data = payload ,
1054+ files = files ,
1055+ )
10211056 )
10221057 )
10231058 finally :
@@ -1034,6 +1069,7 @@ async def send_message(
10341069 self ._parent ._state .store_view (view )
10351070
10361071 self ._responded = True
1072+ await self ._process_callback_response (callback_response )
10371073 if delete_after is not None :
10381074 await self ._parent .delete_original_response (delay = delete_after )
10391075 return self ._parent
@@ -1165,16 +1201,18 @@ async def edit_message(
11651201 adapter = async_context .get ()
11661202 http = parent ._state .http
11671203 try :
1168- await self ._locked_response (
1169- adapter .create_interaction_response (
1170- parent .id ,
1171- parent .token ,
1172- session = parent ._session ,
1173- type = InteractionResponseType .message_update .value ,
1174- proxy = http .proxy ,
1175- proxy_auth = http .proxy_auth ,
1176- data = payload ,
1177- files = files ,
1204+ callback_response : InteractionCallbackResponse = (
1205+ await self ._locked_response (
1206+ adapter .create_interaction_response (
1207+ parent .id ,
1208+ parent .token ,
1209+ session = parent ._session ,
1210+ type = InteractionResponseType .message_update .value ,
1211+ proxy = http .proxy ,
1212+ proxy_auth = http .proxy_auth ,
1213+ data = payload ,
1214+ files = files ,
1215+ )
11781216 )
11791217 )
11801218 finally :
@@ -1187,6 +1225,7 @@ async def edit_message(
11871225 state .store_view (view , message_id )
11881226
11891227 self ._responded = True
1228+ await self ._process_callback_response (callback_response )
11901229 if delete_after is not None :
11911230 await self ._parent .delete_original_response (delay = delete_after )
11921231
@@ -1222,7 +1261,7 @@ async def send_autocomplete_result(
12221261
12231262 adapter = async_context .get ()
12241263 http = parent ._state .http
1225- await self ._locked_response (
1264+ callback_response : InteractionCallbackResponse = await self ._locked_response (
12261265 adapter .create_interaction_response (
12271266 parent .id ,
12281267 parent .token ,
@@ -1235,6 +1274,7 @@ async def send_autocomplete_result(
12351274 )
12361275
12371276 self ._responded = True
1277+ await self ._process_callback_response (callback_response )
12381278
12391279 async def send_modal (self , modal : Modal ) -> Interaction :
12401280 """|coro|
@@ -1261,7 +1301,7 @@ async def send_modal(self, modal: Modal) -> Interaction:
12611301 payload = modal .to_dict ()
12621302 adapter = async_context .get ()
12631303 http = parent ._state .http
1264- await self ._locked_response (
1304+ callback_response : InteractionCallbackResponse = await self ._locked_response (
12651305 adapter .create_interaction_response (
12661306 parent .id ,
12671307 parent .token ,
@@ -1273,6 +1313,7 @@ async def send_modal(self, modal: Modal) -> Interaction:
12731313 )
12741314 )
12751315 self ._responded = True
1316+ await self ._process_callback_response (callback_response )
12761317 self ._parent ._state .store_modal (modal , self ._parent .user .id )
12771318 return self ._parent
12781319
@@ -1300,7 +1341,7 @@ async def premium_required(self) -> Interaction:
13001341
13011342 adapter = async_context .get ()
13021343 http = parent ._state .http
1303- await self ._locked_response (
1344+ callback_response : InteractionCallbackResponse = await self ._locked_response (
13041345 adapter .create_interaction_response (
13051346 parent .id ,
13061347 parent .token ,
@@ -1311,9 +1352,10 @@ async def premium_required(self) -> Interaction:
13111352 )
13121353 )
13131354 self ._responded = True
1355+ await self ._process_callback_response (callback_response )
13141356 return self ._parent
13151357
1316- async def _locked_response (self , coro : Coroutine [Any , Any , Any ]) -> None :
1358+ async def _locked_response (self , coro : Coroutine [Any , Any , Any ]) -> Any :
13171359 """|coro|
13181360
13191361 Wraps a response and makes sure that it's locked while executing.
@@ -1323,16 +1365,24 @@ async def _locked_response(self, coro: Coroutine[Any, Any, Any]) -> None:
13231365 coro: Coroutine[Any]
13241366 The coroutine to wrap.
13251367
1368+ Returns
1369+ -------
1370+ Any
1371+ The result of the coroutine.
1372+
13261373 Raises
13271374 ------
13281375 InteractionResponded
13291376 This interaction has already been responded to before.
1377+
1378+ .. versionchanged:: 2.7
1379+ Return the result of the coroutine
13301380 """
13311381 async with self ._response_lock :
13321382 if self .is_done ():
13331383 coro .close () # cleanup un-awaited coroutine
13341384 raise InteractionResponded (self ._parent )
1335- await coro
1385+ return await coro
13361386
13371387
13381388class _InteractionMessageState :
@@ -1646,3 +1696,36 @@ def guild(self) -> Guild | None:
16461696 if not self .guild_id :
16471697 return None
16481698 return self ._state ._get_guild (self .guild_id )
1699+
1700+
1701+ class InteractionCallback :
1702+ """Information about the status of the interaction response.
1703+
1704+ .. versionadded:: 2.7
1705+ """
1706+
1707+ def __init__ (self , data : InteractionCallbackPayload ):
1708+ self ._response_message_loading : bool = data .get (
1709+ "response_message_loading" , False
1710+ )
1711+ self ._response_message_ephemeral : bool = data .get (
1712+ "response_message_ephemeral" , False
1713+ )
1714+
1715+ def __repr__ (self ):
1716+ return (
1717+ f"<InteractionCallback "
1718+ f"_response_message_loading={ self ._response_message_loading } "
1719+ f"_response_message_ephemeral={ self ._response_message_ephemeral } >"
1720+ )
1721+
1722+ def is_loading (self ) -> bool :
1723+ """Indicates whether the response message is in a loading state."""
1724+ return self ._response_message_loading
1725+
1726+ def is_ephemeral (self ) -> bool :
1727+ """Indicates whether the response message is ephemeral.
1728+
1729+ This might be useful for determining if the message was forced to be ephemeral.
1730+ """
1731+ return self ._response_message_ephemeral
0 commit comments