From f60e37ca284001683e6262302baf320a5b02ee92 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Thu, 18 Sep 2025 20:50:05 -0700 Subject: [PATCH 01/21] feat(web-api): add chat_{appendStream|startStream|stopStream} methods (#1745) Co-authored-by: William Bergamin --- slack_sdk/web/async_client.py | 121 ++++++++++++++---- slack_sdk/web/client.py | 121 ++++++++++++++---- slack_sdk/web/legacy_client.py | 121 ++++++++++++++---- .../web/test_web_client_coverage.py | 16 ++- 4 files changed, 299 insertions(+), 80 deletions(-) diff --git a/slack_sdk/web/async_client.py b/slack_sdk/web/async_client.py index f9a31428a..a3564e358 100644 --- a/slack_sdk/web/async_client.py +++ b/slack_sdk/web/async_client.py @@ -2620,6 +2620,26 @@ async def channels_unarchive( # -------------------------- + async def chat_appendStream( + self, + *, + channel: str, + ts: str, + markdown_text: str, + **kwargs, + ) -> AsyncSlackResponse: + """Appends text to an existing streaming conversation. + https://api.slack.com/methods/chat.appendStream + """ + kwargs.update( + { + "channel": channel, + "ts": ts, + "markdown_text": markdown_text, + } + ) + return await self.api_call("chat.appendStream", params=kwargs) + async def chat_delete( self, *, @@ -2824,6 +2844,81 @@ async def chat_scheduleMessage( # NOTE: intentionally using json over params for the API methods using blocks/attachments return await self.api_call("chat.scheduleMessage", json=kwargs) + async def chat_scheduledMessages_list( + self, + *, + channel: Optional[str] = None, + cursor: Optional[str] = None, + latest: Optional[str] = None, + limit: Optional[int] = None, + oldest: Optional[str] = None, + team_id: Optional[str] = None, + **kwargs, + ) -> AsyncSlackResponse: + """Lists all scheduled messages. + https://api.slack.com/methods/chat.scheduledMessages.list + """ + kwargs.update( + { + "channel": channel, + "cursor": cursor, + "latest": latest, + "limit": limit, + "oldest": oldest, + "team_id": team_id, + } + ) + return await self.api_call("chat.scheduledMessages.list", params=kwargs) + + async def chat_startStream( + self, + *, + channel: str, + thread_ts: Optional[str] = None, + markdown_text: Optional[str] = None, + unfurl_links: Optional[bool] = None, + unfurl_media: Optional[bool] = None, + **kwargs, + ) -> AsyncSlackResponse: + """Starts a new streaming conversation. + https://api.slack.com/methods/chat.startStream + """ + kwargs.update( + { + "channel": channel, + "thread_ts": thread_ts, + "markdown_text": markdown_text, + "unfurl_links": unfurl_links, + "unfurl_media": unfurl_media, + } + ) + return await self.api_call("chat.startStream", params=kwargs) + + async def chat_stopStream( + self, + *, + channel: str, + ts: str, + markdown_text: Optional[str] = None, + blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, + metadata: Optional[Union[Dict, Metadata]] = None, + **kwargs, + ) -> AsyncSlackResponse: + """Stops a streaming conversation. + https://api.slack.com/methods/chat.stopStream + """ + kwargs.update( + { + "channel": channel, + "ts": ts, + "markdown_text": markdown_text, + "blocks": blocks, + "metadata": metadata, + } + ) + _parse_web_class_objects(kwargs) + return await self.api_call("chat.stopStream", params=kwargs) + async def chat_unfurl( self, *, @@ -2904,32 +2999,6 @@ async def chat_update( # NOTE: intentionally using json over params for API methods using blocks/attachments return await self.api_call("chat.update", json=kwargs) - async def chat_scheduledMessages_list( - self, - *, - channel: Optional[str] = None, - cursor: Optional[str] = None, - latest: Optional[str] = None, - limit: Optional[int] = None, - oldest: Optional[str] = None, - team_id: Optional[str] = None, - **kwargs, - ) -> AsyncSlackResponse: - """Lists all scheduled messages. - https://api.slack.com/methods/chat.scheduledMessages.list - """ - kwargs.update( - { - "channel": channel, - "cursor": cursor, - "latest": latest, - "limit": limit, - "oldest": oldest, - "team_id": team_id, - } - ) - return await self.api_call("chat.scheduledMessages.list", params=kwargs) - async def conversations_acceptSharedInvite( self, *, diff --git a/slack_sdk/web/client.py b/slack_sdk/web/client.py index 1747e0d45..c1d8119c9 100644 --- a/slack_sdk/web/client.py +++ b/slack_sdk/web/client.py @@ -2610,6 +2610,26 @@ def channels_unarchive( # -------------------------- + def chat_appendStream( + self, + *, + channel: str, + ts: str, + markdown_text: str, + **kwargs, + ) -> SlackResponse: + """Appends text to an existing streaming conversation. + https://api.slack.com/methods/chat.appendStream + """ + kwargs.update( + { + "channel": channel, + "ts": ts, + "markdown_text": markdown_text, + } + ) + return self.api_call("chat.appendStream", params=kwargs) + def chat_delete( self, *, @@ -2814,6 +2834,81 @@ def chat_scheduleMessage( # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.scheduleMessage", json=kwargs) + def chat_scheduledMessages_list( + self, + *, + channel: Optional[str] = None, + cursor: Optional[str] = None, + latest: Optional[str] = None, + limit: Optional[int] = None, + oldest: Optional[str] = None, + team_id: Optional[str] = None, + **kwargs, + ) -> SlackResponse: + """Lists all scheduled messages. + https://api.slack.com/methods/chat.scheduledMessages.list + """ + kwargs.update( + { + "channel": channel, + "cursor": cursor, + "latest": latest, + "limit": limit, + "oldest": oldest, + "team_id": team_id, + } + ) + return self.api_call("chat.scheduledMessages.list", params=kwargs) + + def chat_startStream( + self, + *, + channel: str, + thread_ts: Optional[str] = None, + markdown_text: Optional[str] = None, + unfurl_links: Optional[bool] = None, + unfurl_media: Optional[bool] = None, + **kwargs, + ) -> SlackResponse: + """Starts a new streaming conversation. + https://api.slack.com/methods/chat.startStream + """ + kwargs.update( + { + "channel": channel, + "thread_ts": thread_ts, + "markdown_text": markdown_text, + "unfurl_links": unfurl_links, + "unfurl_media": unfurl_media, + } + ) + return self.api_call("chat.startStream", params=kwargs) + + def chat_stopStream( + self, + *, + channel: str, + ts: str, + markdown_text: Optional[str] = None, + blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, + metadata: Optional[Union[Dict, Metadata]] = None, + **kwargs, + ) -> SlackResponse: + """Stops a streaming conversation. + https://api.slack.com/methods/chat.stopStream + """ + kwargs.update( + { + "channel": channel, + "ts": ts, + "markdown_text": markdown_text, + "blocks": blocks, + "metadata": metadata, + } + ) + _parse_web_class_objects(kwargs) + return self.api_call("chat.stopStream", params=kwargs) + def chat_unfurl( self, *, @@ -2894,32 +2989,6 @@ def chat_update( # NOTE: intentionally using json over params for API methods using blocks/attachments return self.api_call("chat.update", json=kwargs) - def chat_scheduledMessages_list( - self, - *, - channel: Optional[str] = None, - cursor: Optional[str] = None, - latest: Optional[str] = None, - limit: Optional[int] = None, - oldest: Optional[str] = None, - team_id: Optional[str] = None, - **kwargs, - ) -> SlackResponse: - """Lists all scheduled messages. - https://api.slack.com/methods/chat.scheduledMessages.list - """ - kwargs.update( - { - "channel": channel, - "cursor": cursor, - "latest": latest, - "limit": limit, - "oldest": oldest, - "team_id": team_id, - } - ) - return self.api_call("chat.scheduledMessages.list", params=kwargs) - def conversations_acceptSharedInvite( self, *, diff --git a/slack_sdk/web/legacy_client.py b/slack_sdk/web/legacy_client.py index ed2177644..637ca0a88 100644 --- a/slack_sdk/web/legacy_client.py +++ b/slack_sdk/web/legacy_client.py @@ -2622,6 +2622,26 @@ def channels_unarchive( # -------------------------- + def chat_appendStream( + self, + *, + channel: str, + ts: str, + markdown_text: str, + **kwargs, + ) -> Union[Future, SlackResponse]: + """Appends text to an existing streaming conversation. + https://api.slack.com/methods/chat.appendStream + """ + kwargs.update( + { + "channel": channel, + "ts": ts, + "markdown_text": markdown_text, + } + ) + return self.api_call("chat.appendStream", params=kwargs) + def chat_delete( self, *, @@ -2826,6 +2846,81 @@ def chat_scheduleMessage( # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.scheduleMessage", json=kwargs) + def chat_scheduledMessages_list( + self, + *, + channel: Optional[str] = None, + cursor: Optional[str] = None, + latest: Optional[str] = None, + limit: Optional[int] = None, + oldest: Optional[str] = None, + team_id: Optional[str] = None, + **kwargs, + ) -> Union[Future, SlackResponse]: + """Lists all scheduled messages. + https://api.slack.com/methods/chat.scheduledMessages.list + """ + kwargs.update( + { + "channel": channel, + "cursor": cursor, + "latest": latest, + "limit": limit, + "oldest": oldest, + "team_id": team_id, + } + ) + return self.api_call("chat.scheduledMessages.list", params=kwargs) + + def chat_startStream( + self, + *, + channel: str, + thread_ts: Optional[str] = None, + markdown_text: Optional[str] = None, + unfurl_links: Optional[bool] = None, + unfurl_media: Optional[bool] = None, + **kwargs, + ) -> Union[Future, SlackResponse]: + """Starts a new streaming conversation. + https://api.slack.com/methods/chat.startStream + """ + kwargs.update( + { + "channel": channel, + "thread_ts": thread_ts, + "markdown_text": markdown_text, + "unfurl_links": unfurl_links, + "unfurl_media": unfurl_media, + } + ) + return self.api_call("chat.startStream", params=kwargs) + + def chat_stopStream( + self, + *, + channel: str, + ts: str, + markdown_text: Optional[str] = None, + blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, + metadata: Optional[Union[Dict, Metadata]] = None, + **kwargs, + ) -> Union[Future, SlackResponse]: + """Stops a streaming conversation. + https://api.slack.com/methods/chat.stopStream + """ + kwargs.update( + { + "channel": channel, + "ts": ts, + "markdown_text": markdown_text, + "blocks": blocks, + "metadata": metadata, + } + ) + _parse_web_class_objects(kwargs) + return self.api_call("chat.stopStream", params=kwargs) + def chat_unfurl( self, *, @@ -2906,32 +3001,6 @@ def chat_update( # NOTE: intentionally using json over params for API methods using blocks/attachments return self.api_call("chat.update", json=kwargs) - def chat_scheduledMessages_list( - self, - *, - channel: Optional[str] = None, - cursor: Optional[str] = None, - latest: Optional[str] = None, - limit: Optional[int] = None, - oldest: Optional[str] = None, - team_id: Optional[str] = None, - **kwargs, - ) -> Union[Future, SlackResponse]: - """Lists all scheduled messages. - https://api.slack.com/methods/chat.scheduledMessages.list - """ - kwargs.update( - { - "channel": channel, - "cursor": cursor, - "latest": latest, - "limit": limit, - "oldest": oldest, - "team_id": team_id, - } - ) - return self.api_call("chat.scheduledMessages.list", params=kwargs) - def conversations_acceptSharedInvite( self, *, diff --git a/tests/slack_sdk_async/web/test_web_client_coverage.py b/tests/slack_sdk_async/web/test_web_client_coverage.py index f6410315e..3900e34a2 100644 --- a/tests/slack_sdk_async/web/test_web_client_coverage.py +++ b/tests/slack_sdk_async/web/test_web_client_coverage.py @@ -13,9 +13,9 @@ class TestWebClientCoverage(unittest.TestCase): - # 292 endpoints as of July 22, 2025 + # 295 endpoints as of September 17, 2025 # Can be fetched by running `var methodNames = [].slice.call(document.getElementsByClassName('apiReferenceFilterableList__listItemLink')).map(e => e.href.replace("https://api.slack.com/methods/", ""));console.log(methodNames.toString());console.log(methodNames.length);` on https://api.slack.com/methods - all_api_methods = "admin.analytics.getFile,admin.apps.activities.list,admin.apps.approve,admin.apps.clearResolution,admin.apps.restrict,admin.apps.uninstall,admin.apps.approved.list,admin.apps.config.lookup,admin.apps.config.set,admin.apps.requests.cancel,admin.apps.requests.list,admin.apps.restricted.list,admin.audit.anomaly.allow.getItem,admin.audit.anomaly.allow.updateItem,admin.auth.policy.assignEntities,admin.auth.policy.getEntities,admin.auth.policy.removeEntities,admin.barriers.create,admin.barriers.delete,admin.barriers.list,admin.barriers.update,admin.conversations.archive,admin.conversations.bulkArchive,admin.conversations.bulkDelete,admin.conversations.bulkMove,admin.conversations.convertToPrivate,admin.conversations.convertToPublic,admin.conversations.create,admin.conversations.createForObjects,admin.conversations.delete,admin.conversations.disconnectShared,admin.conversations.getConversationPrefs,admin.conversations.getCustomRetention,admin.conversations.getTeams,admin.conversations.invite,admin.conversations.linkObjects,admin.conversations.lookup,admin.conversations.removeCustomRetention,admin.conversations.rename,admin.conversations.search,admin.conversations.setConversationPrefs,admin.conversations.setCustomRetention,admin.conversations.setTeams,admin.conversations.unarchive,admin.conversations.unlinkObjects,admin.conversations.ekm.listOriginalConnectedChannelInfo,admin.conversations.restrictAccess.addGroup,admin.conversations.restrictAccess.listGroups,admin.conversations.restrictAccess.removeGroup,admin.emoji.add,admin.emoji.addAlias,admin.emoji.list,admin.emoji.remove,admin.emoji.rename,admin.functions.list,admin.functions.permissions.lookup,admin.functions.permissions.set,admin.inviteRequests.approve,admin.inviteRequests.deny,admin.inviteRequests.list,admin.inviteRequests.approved.list,admin.inviteRequests.denied.list,admin.roles.addAssignments,admin.roles.listAssignments,admin.roles.removeAssignments,admin.teams.admins.list,admin.teams.create,admin.teams.list,admin.teams.owners.list,admin.teams.settings.info,admin.teams.settings.setDefaultChannels,admin.teams.settings.setDescription,admin.teams.settings.setDiscoverability,admin.teams.settings.setIcon,admin.teams.settings.setName,admin.usergroups.addChannels,admin.usergroups.addTeams,admin.usergroups.listChannels,admin.usergroups.removeChannels,admin.users.assign,admin.users.invite,admin.users.list,admin.users.remove,admin.users.setAdmin,admin.users.setExpiration,admin.users.setOwner,admin.users.setRegular,admin.users.session.clearSettings,admin.users.session.getSettings,admin.users.session.invalidate,admin.users.session.list,admin.users.session.reset,admin.users.session.resetBulk,admin.users.session.setSettings,admin.users.unsupportedVersions.export,admin.workflows.collaborators.add,admin.workflows.collaborators.remove,admin.workflows.permissions.lookup,admin.workflows.search,admin.workflows.unpublish,admin.workflows.triggers.types.permissions.lookup,admin.workflows.triggers.types.permissions.set,api.test,apps.activities.list,apps.auth.external.delete,apps.auth.external.get,apps.connections.open,apps.uninstall,apps.datastore.bulkDelete,apps.datastore.bulkGet,apps.datastore.bulkPut,apps.datastore.count,apps.datastore.delete,apps.datastore.get,apps.datastore.put,apps.datastore.query,apps.datastore.update,apps.event.authorizations.list,apps.manifest.create,apps.manifest.delete,apps.manifest.export,apps.manifest.update,apps.manifest.validate,assistant.search.context,assistant.threads.setStatus,assistant.threads.setSuggestedPrompts,assistant.threads.setTitle,auth.revoke,auth.test,auth.teams.list,bookmarks.add,bookmarks.edit,bookmarks.list,bookmarks.remove,bots.info,calls.add,calls.end,calls.info,calls.update,calls.participants.add,calls.participants.remove,canvases.access.delete,canvases.access.set,canvases.create,canvases.delete,canvases.edit,canvases.sections.lookup,channels.mark,chat.delete,chat.deleteScheduledMessage,chat.getPermalink,chat.meMessage,chat.postEphemeral,chat.postMessage,chat.scheduleMessage,chat.unfurl,chat.update,chat.scheduledMessages.list,conversations.acceptSharedInvite,conversations.approveSharedInvite,conversations.archive,conversations.close,conversations.create,conversations.declineSharedInvite,conversations.history,conversations.info,conversations.invite,conversations.inviteShared,conversations.join,conversations.kick,conversations.leave,conversations.list,conversations.listConnectInvites,conversations.mark,conversations.members,conversations.open,conversations.rename,conversations.replies,conversations.setPurpose,conversations.setTopic,conversations.unarchive,conversations.canvases.create,conversations.externalInvitePermissions.set,conversations.requestSharedInvite.approve,conversations.requestSharedInvite.deny,conversations.requestSharedInvite.list,dialog.open,dnd.endDnd,dnd.endSnooze,dnd.info,dnd.setSnooze,dnd.teamInfo,emoji.list,files.completeUploadExternal,files.delete,files.getUploadURLExternal,files.info,files.list,files.revokePublicURL,files.sharedPublicURL,files.upload,files.comments.delete,files.remote.add,files.remote.info,files.remote.list,files.remote.remove,files.remote.share,files.remote.update,functions.completeError,functions.completeSuccess,functions.distributions.permissions.add,functions.distributions.permissions.list,functions.distributions.permissions.remove,functions.distributions.permissions.set,functions.workflows.steps.list,functions.workflows.steps.responses.export,groups.mark,migration.exchange,oauth.access,oauth.v2.access,oauth.v2.exchange,openid.connect.token,openid.connect.userInfo,pins.add,pins.list,pins.remove,reactions.add,reactions.get,reactions.list,reactions.remove,reminders.add,reminders.complete,reminders.delete,reminders.info,reminders.list,rtm.connect,rtm.start,search.all,search.files,search.messages,stars.add,stars.list,stars.remove,team.accessLogs,team.billableInfo,team.info,team.integrationLogs,team.billing.info,team.externalTeams.disconnect,team.externalTeams.list,team.preferences.list,team.profile.get,tooling.tokens.rotate,usergroups.create,usergroups.disable,usergroups.enable,usergroups.list,usergroups.update,usergroups.users.list,usergroups.users.update,users.conversations,users.deletePhoto,users.getPresence,users.identity,users.info,users.list,users.lookupByEmail,users.setActive,users.setPhoto,users.setPresence,users.discoverableContacts.lookup,users.profile.get,users.profile.set,views.open,views.publish,views.push,views.update,workflows.featured.add,workflows.featured.list,workflows.featured.remove,workflows.featured.set,workflows.stepCompleted,workflows.stepFailed,workflows.updateStep,workflows.triggers.permissions.add,workflows.triggers.permissions.list,workflows.triggers.permissions.remove,workflows.triggers.permissions.set,im.list,im.mark,mpim.list,mpim.mark".split( + all_api_methods = "admin.analytics.getFile,admin.apps.activities.list,admin.apps.approve,admin.apps.clearResolution,admin.apps.restrict,admin.apps.uninstall,admin.apps.approved.list,admin.apps.config.lookup,admin.apps.config.set,admin.apps.requests.cancel,admin.apps.requests.list,admin.apps.restricted.list,admin.audit.anomaly.allow.getItem,admin.audit.anomaly.allow.updateItem,admin.auth.policy.assignEntities,admin.auth.policy.getEntities,admin.auth.policy.removeEntities,admin.barriers.create,admin.barriers.delete,admin.barriers.list,admin.barriers.update,admin.conversations.archive,admin.conversations.bulkArchive,admin.conversations.bulkDelete,admin.conversations.bulkMove,admin.conversations.convertToPrivate,admin.conversations.convertToPublic,admin.conversations.create,admin.conversations.createForObjects,admin.conversations.delete,admin.conversations.disconnectShared,admin.conversations.getConversationPrefs,admin.conversations.getCustomRetention,admin.conversations.getTeams,admin.conversations.invite,admin.conversations.linkObjects,admin.conversations.lookup,admin.conversations.removeCustomRetention,admin.conversations.rename,admin.conversations.search,admin.conversations.setConversationPrefs,admin.conversations.setCustomRetention,admin.conversations.setTeams,admin.conversations.unarchive,admin.conversations.unlinkObjects,admin.conversations.ekm.listOriginalConnectedChannelInfo,admin.conversations.restrictAccess.addGroup,admin.conversations.restrictAccess.listGroups,admin.conversations.restrictAccess.removeGroup,admin.emoji.add,admin.emoji.addAlias,admin.emoji.list,admin.emoji.remove,admin.emoji.rename,admin.functions.list,admin.functions.permissions.lookup,admin.functions.permissions.set,admin.inviteRequests.approve,admin.inviteRequests.deny,admin.inviteRequests.list,admin.inviteRequests.approved.list,admin.inviteRequests.denied.list,admin.roles.addAssignments,admin.roles.listAssignments,admin.roles.removeAssignments,admin.teams.admins.list,admin.teams.create,admin.teams.list,admin.teams.owners.list,admin.teams.settings.info,admin.teams.settings.setDefaultChannels,admin.teams.settings.setDescription,admin.teams.settings.setDiscoverability,admin.teams.settings.setIcon,admin.teams.settings.setName,admin.usergroups.addChannels,admin.usergroups.addTeams,admin.usergroups.listChannels,admin.usergroups.removeChannels,admin.users.assign,admin.users.invite,admin.users.list,admin.users.remove,admin.users.setAdmin,admin.users.setExpiration,admin.users.setOwner,admin.users.setRegular,admin.users.session.clearSettings,admin.users.session.getSettings,admin.users.session.invalidate,admin.users.session.list,admin.users.session.reset,admin.users.session.resetBulk,admin.users.session.setSettings,admin.users.unsupportedVersions.export,admin.workflows.collaborators.add,admin.workflows.collaborators.remove,admin.workflows.permissions.lookup,admin.workflows.search,admin.workflows.unpublish,admin.workflows.triggers.types.permissions.lookup,admin.workflows.triggers.types.permissions.set,api.test,apps.activities.list,apps.auth.external.delete,apps.auth.external.get,apps.connections.open,apps.uninstall,apps.datastore.bulkDelete,apps.datastore.bulkGet,apps.datastore.bulkPut,apps.datastore.count,apps.datastore.delete,apps.datastore.get,apps.datastore.put,apps.datastore.query,apps.datastore.update,apps.event.authorizations.list,apps.manifest.create,apps.manifest.delete,apps.manifest.export,apps.manifest.update,apps.manifest.validate,assistant.search.context,assistant.threads.setStatus,assistant.threads.setSuggestedPrompts,assistant.threads.setTitle,auth.revoke,auth.test,auth.teams.list,bookmarks.add,bookmarks.edit,bookmarks.list,bookmarks.remove,bots.info,calls.add,calls.end,calls.info,calls.update,calls.participants.add,calls.participants.remove,canvases.access.delete,canvases.access.set,canvases.create,canvases.delete,canvases.edit,canvases.sections.lookup,channels.mark,chat.appendStream,chat.delete,chat.deleteScheduledMessage,chat.getPermalink,chat.meMessage,chat.postEphemeral,chat.postMessage,chat.scheduleMessage,chat.scheduledMessages.list,chat.startStream,chat.stopStream,chat.unfurl,chat.update,conversations.acceptSharedInvite,conversations.approveSharedInvite,conversations.archive,conversations.close,conversations.create,conversations.declineSharedInvite,conversations.history,conversations.info,conversations.invite,conversations.inviteShared,conversations.join,conversations.kick,conversations.leave,conversations.list,conversations.listConnectInvites,conversations.mark,conversations.members,conversations.open,conversations.rename,conversations.replies,conversations.setPurpose,conversations.setTopic,conversations.unarchive,conversations.canvases.create,conversations.externalInvitePermissions.set,conversations.requestSharedInvite.approve,conversations.requestSharedInvite.deny,conversations.requestSharedInvite.list,dialog.open,dnd.endDnd,dnd.endSnooze,dnd.info,dnd.setSnooze,dnd.teamInfo,emoji.list,files.completeUploadExternal,files.delete,files.getUploadURLExternal,files.info,files.list,files.revokePublicURL,files.sharedPublicURL,files.upload,files.comments.delete,files.remote.add,files.remote.info,files.remote.list,files.remote.remove,files.remote.share,files.remote.update,functions.completeError,functions.completeSuccess,functions.distributions.permissions.add,functions.distributions.permissions.list,functions.distributions.permissions.remove,functions.distributions.permissions.set,functions.workflows.steps.list,functions.workflows.steps.responses.export,groups.mark,migration.exchange,oauth.access,oauth.v2.access,oauth.v2.exchange,openid.connect.token,openid.connect.userInfo,pins.add,pins.list,pins.remove,reactions.add,reactions.get,reactions.list,reactions.remove,reminders.add,reminders.complete,reminders.delete,reminders.info,reminders.list,rtm.connect,rtm.start,search.all,search.files,search.messages,stars.add,stars.list,stars.remove,team.accessLogs,team.billableInfo,team.info,team.integrationLogs,team.billing.info,team.externalTeams.disconnect,team.externalTeams.list,team.preferences.list,team.profile.get,tooling.tokens.rotate,usergroups.create,usergroups.disable,usergroups.enable,usergroups.list,usergroups.update,usergroups.users.list,usergroups.users.update,users.conversations,users.deletePhoto,users.getPresence,users.identity,users.info,users.list,users.lookupByEmail,users.setActive,users.setPhoto,users.setPresence,users.discoverableContacts.lookup,users.profile.get,users.profile.set,views.open,views.publish,views.push,views.update,workflows.featured.add,workflows.featured.list,workflows.featured.remove,workflows.featured.set,workflows.stepCompleted,workflows.stepFailed,workflows.updateStep,workflows.triggers.permissions.add,workflows.triggers.permissions.list,workflows.triggers.permissions.remove,workflows.triggers.permissions.set,im.list,im.mark,mpim.list,mpim.mark".split( "," ) @@ -540,6 +540,9 @@ async def run_method(self, method_name, method, async_method): elif method_name == "canvases_sections_lookup": self.api_methods_to_call.remove(method(canvas_id="F123", criteria={})["method"]) await async_method(canvas_id="F123", criteria={}) + elif method_name == "chat_appendStream": + self.api_methods_to_call.remove(method(channel="C123", ts="123.123", markdown_text="**bold**")["method"]) + await async_method(channel="C123", ts="123.123", markdown_text="**bold**") elif method_name == "chat_delete": self.api_methods_to_call.remove(method(channel="C123", ts="123.123")["method"]) await async_method(channel="C123", ts="123.123") @@ -561,6 +564,15 @@ async def run_method(self, method_name, method, async_method): elif method_name == "chat_scheduleMessage": self.api_methods_to_call.remove(method(channel="C123", post_at=123, text="Hi")["method"]) await async_method(channel="C123", post_at=123, text="Hi") + elif method_name == "chat_scheduledMessages_list": + self.api_methods_to_call.remove(method()["method"]) + await async_method() + elif method_name == "chat_startStream": + self.api_methods_to_call.remove(method(channel="C123")["method"]) + await async_method(channel="C123") + elif method_name == "chat_stopStream": + self.api_methods_to_call.remove(method(channel="C123", ts="123.123")["method"]) + await async_method(channel="C123", ts="123.123") elif method_name == "chat_unfurl": self.api_methods_to_call.remove( method( From 4a3c0eddbb2998c2f343c134e1df97407bdb7629 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Thu, 18 Sep 2025 21:17:10 -0700 Subject: [PATCH 02/21] feat(web-api): add loading_messages to assistant.threads.setStatus method (#1746) --- slack_sdk/web/async_client.py | 11 +++++++---- slack_sdk/web/client.py | 11 +++++++---- slack_sdk/web/legacy_client.py | 11 +++++++---- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/slack_sdk/web/async_client.py b/slack_sdk/web/async_client.py index a3564e358..0c047892a 100644 --- a/slack_sdk/web/async_client.py +++ b/slack_sdk/web/async_client.py @@ -2075,12 +2075,15 @@ async def assistant_threads_setStatus( channel_id: str, thread_ts: str, status: str, + loading_messages: Optional[List[str]] = None, **kwargs, ) -> AsyncSlackResponse: - """Revokes a token. + """Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus """ - kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "status": status}) + kwargs.update( + {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} + ) return await self.api_call("assistant.threads.setStatus", params=kwargs) async def assistant_threads_setTitle( @@ -2091,7 +2094,7 @@ async def assistant_threads_setTitle( title: str, **kwargs, ) -> AsyncSlackResponse: - """Revokes a token. + """Set the title for the given assistant thread. https://api.slack.com/methods/assistant.threads.setTitle """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "title": title}) @@ -2106,7 +2109,7 @@ async def assistant_threads_setSuggestedPrompts( prompts: List[Dict[str, str]], **kwargs, ) -> AsyncSlackResponse: - """Revokes a token. + """Set suggested prompts for the given assistant thread. https://api.slack.com/methods/assistant.threads.setSuggestedPrompts """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "prompts": prompts}) diff --git a/slack_sdk/web/client.py b/slack_sdk/web/client.py index c1d8119c9..9ff9eeb66 100644 --- a/slack_sdk/web/client.py +++ b/slack_sdk/web/client.py @@ -2065,12 +2065,15 @@ def assistant_threads_setStatus( channel_id: str, thread_ts: str, status: str, + loading_messages: Optional[List[str]] = None, **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus """ - kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "status": status}) + kwargs.update( + {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} + ) return self.api_call("assistant.threads.setStatus", params=kwargs) def assistant_threads_setTitle( @@ -2081,7 +2084,7 @@ def assistant_threads_setTitle( title: str, **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set the title for the given assistant thread. https://api.slack.com/methods/assistant.threads.setTitle """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "title": title}) @@ -2096,7 +2099,7 @@ def assistant_threads_setSuggestedPrompts( prompts: List[Dict[str, str]], **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set suggested prompts for the given assistant thread. https://api.slack.com/methods/assistant.threads.setSuggestedPrompts """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "prompts": prompts}) diff --git a/slack_sdk/web/legacy_client.py b/slack_sdk/web/legacy_client.py index 637ca0a88..e83f82a1a 100644 --- a/slack_sdk/web/legacy_client.py +++ b/slack_sdk/web/legacy_client.py @@ -2077,12 +2077,15 @@ def assistant_threads_setStatus( channel_id: str, thread_ts: str, status: str, + loading_messages: Optional[List[str]] = None, **kwargs, ) -> Union[Future, SlackResponse]: - """Revokes a token. + """Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus """ - kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "status": status}) + kwargs.update( + {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} + ) return self.api_call("assistant.threads.setStatus", params=kwargs) def assistant_threads_setTitle( @@ -2093,7 +2096,7 @@ def assistant_threads_setTitle( title: str, **kwargs, ) -> Union[Future, SlackResponse]: - """Revokes a token. + """Set the title for the given assistant thread. https://api.slack.com/methods/assistant.threads.setTitle """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "title": title}) @@ -2108,7 +2111,7 @@ def assistant_threads_setSuggestedPrompts( prompts: List[Dict[str, str]], **kwargs, ) -> Union[Future, SlackResponse]: - """Revokes a token. + """Set suggested prompts for the given assistant thread. https://api.slack.com/methods/assistant.threads.setSuggestedPrompts """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "prompts": prompts}) From 852377bc0332f5f8fc705aa8069fc60984958c11 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 19 Sep 2025 16:29:50 -0700 Subject: [PATCH 03/21] chore(release): version 3.36.0.dev0 --- docs/reference/index.html | 494 +++++++++++++++--- .../models/blocks/basic_components.html | 12 +- docs/reference/models/blocks/index.html | 12 +- docs/reference/models/dialoags.html | 4 +- docs/reference/models/dialogs/index.html | 4 +- .../async_cacheable_installation_store.html | 8 +- .../cacheable_installation_store.html | 8 +- docs/reference/socket_mode/client.html | 4 +- .../socket_mode/websocket_client/index.html | 6 +- docs/reference/web/async_client.html | 486 +++++++++++++++-- docs/reference/web/client.html | 486 +++++++++++++++-- docs/reference/web/index.html | 486 +++++++++++++++-- docs/reference/web/internal_utils.html | 4 +- docs/reference/web/legacy_client.html | 486 +++++++++++++++-- docs/reference/webhook/client.html | 8 +- docs/reference/webhook/index.html | 8 +- slack_sdk/version.py | 2 +- 17 files changed, 2199 insertions(+), 319 deletions(-) diff --git a/docs/reference/index.html b/docs/reference/index.html index 8b9b9e3f5..f9829dfc4 100644 --- a/docs/reference/index.html +++ b/docs/reference/index.html @@ -1856,7 +1856,7 @@

Classes

def admin_users_list( self, *, - team_id: str, + team_id: Optional[str] = None, include_deactivated_user_workspaces: Optional[bool] = None, is_active: Optional[bool] = None, cursor: Optional[str] = None, @@ -2201,12 +2201,15 @@

Classes

channel_id: str, thread_ts: str, status: str, + loading_messages: Optional[List[str]] = None, **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus """ - kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "status": status}) + kwargs.update( + {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} + ) return self.api_call("assistant.threads.setStatus", params=kwargs) def assistant_threads_setTitle( @@ -2217,7 +2220,7 @@

Classes

title: str, **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set the title for the given assistant thread. https://api.slack.com/methods/assistant.threads.setTitle """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "title": title}) @@ -2232,7 +2235,7 @@

Classes

prompts: List[Dict[str, str]], **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set suggested prompts for the given assistant thread. https://api.slack.com/methods/assistant.threads.setSuggestedPrompts """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "prompts": prompts}) @@ -2746,6 +2749,26 @@

Classes

# -------------------------- + def chat_appendStream( + self, + *, + channel: str, + ts: str, + markdown_text: str, + **kwargs, + ) -> SlackResponse: + """Appends text to an existing streaming conversation. + https://api.slack.com/methods/chat.appendStream + """ + kwargs.update( + { + "channel": channel, + "ts": ts, + "markdown_text": markdown_text, + } + ) + return self.api_call("chat.appendStream", params=kwargs) + def chat_delete( self, *, @@ -2821,6 +2844,7 @@

Classes

link_names: Optional[bool] = None, username: Optional[str] = None, parse: Optional[str] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Sends an ephemeral message to a user in a channel. @@ -2840,11 +2864,12 @@

Classes

"link_names": link_names, "username": username, "parse": parse, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postEphemeral", kwargs) + _warn_if_message_text_content_is_missing("chat.postEphemeral", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.postEphemeral", json=kwargs) @@ -2868,6 +2893,7 @@

Classes

username: Optional[str] = None, parse: Optional[str] = None, # none, full metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Sends a message to a channel. @@ -2892,11 +2918,12 @@

Classes

"username": username, "parse": parse, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.postMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.postMessage", json=kwargs) @@ -2905,7 +2932,7 @@

Classes

*, channel: str, post_at: Union[str, int], - text: str, + text: Optional[str] = None, as_user: Optional[bool] = None, attachments: Optional[Union[str, Sequence[Union[Dict, Attachment]]]] = None, blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, @@ -2916,6 +2943,7 @@

Classes

unfurl_media: Optional[bool] = None, link_names: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Schedules a message. @@ -2936,14 +2964,90 @@

Classes

"unfurl_media": unfurl_media, "link_names": link_names, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.scheduleMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.scheduleMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.scheduleMessage", json=kwargs) + def chat_scheduledMessages_list( + self, + *, + channel: Optional[str] = None, + cursor: Optional[str] = None, + latest: Optional[str] = None, + limit: Optional[int] = None, + oldest: Optional[str] = None, + team_id: Optional[str] = None, + **kwargs, + ) -> SlackResponse: + """Lists all scheduled messages. + https://api.slack.com/methods/chat.scheduledMessages.list + """ + kwargs.update( + { + "channel": channel, + "cursor": cursor, + "latest": latest, + "limit": limit, + "oldest": oldest, + "team_id": team_id, + } + ) + return self.api_call("chat.scheduledMessages.list", params=kwargs) + + def chat_startStream( + self, + *, + channel: str, + thread_ts: Optional[str] = None, + markdown_text: Optional[str] = None, + unfurl_links: Optional[bool] = None, + unfurl_media: Optional[bool] = None, + **kwargs, + ) -> SlackResponse: + """Starts a new streaming conversation. + https://api.slack.com/methods/chat.startStream + """ + kwargs.update( + { + "channel": channel, + "thread_ts": thread_ts, + "markdown_text": markdown_text, + "unfurl_links": unfurl_links, + "unfurl_media": unfurl_media, + } + ) + return self.api_call("chat.startStream", params=kwargs) + + def chat_stopStream( + self, + *, + channel: str, + ts: str, + markdown_text: Optional[str] = None, + blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, + metadata: Optional[Union[Dict, Metadata]] = None, + **kwargs, + ) -> SlackResponse: + """Stops a streaming conversation. + https://api.slack.com/methods/chat.stopStream + """ + kwargs.update( + { + "channel": channel, + "ts": ts, + "markdown_text": markdown_text, + "blocks": blocks, + "metadata": metadata, + } + ) + _parse_web_class_objects(kwargs) + return self.api_call("chat.stopStream", params=kwargs) + def chat_unfurl( self, *, @@ -2993,6 +3097,7 @@

Classes

parse: Optional[str] = None, # none, full reply_broadcast: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Updates a message in a channel. @@ -3010,6 +3115,7 @@

Classes

"parse": parse, "reply_broadcast": reply_broadcast, "metadata": metadata, + "markdown_text": markdown_text, } ) if isinstance(file_ids, (list, tuple)): @@ -3018,36 +3124,10 @@

Classes

kwargs.update({"file_ids": file_ids}) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.update", kwargs) + _warn_if_message_text_content_is_missing("chat.update", kwargs) # NOTE: intentionally using json over params for API methods using blocks/attachments return self.api_call("chat.update", json=kwargs) - def chat_scheduledMessages_list( - self, - *, - channel: Optional[str] = None, - cursor: Optional[str] = None, - latest: Optional[str] = None, - limit: Optional[int] = None, - oldest: Optional[str] = None, - team_id: Optional[str] = None, - **kwargs, - ) -> SlackResponse: - """Lists all scheduled messages. - https://api.slack.com/methods/chat.scheduledMessages.list - """ - kwargs.update( - { - "channel": channel, - "cursor": cursor, - "latest": latest, - "limit": limit, - "oldest": oldest, - "team_id": team_id, - } - ) - return self.api_call("chat.scheduledMessages.list", params=kwargs) - def conversations_acceptSharedInvite( self, *, @@ -5542,6 +5622,72 @@

Classes

# NOTE: Intentionally using json for the "view" parameter return self.api_call("views.publish", json=kwargs) + def workflows_featured_add( + self, + *, + channel_id: str, + trigger_ids: Union[str, Sequence[str]], + **kwargs, + ) -> SlackResponse: + """Add featured workflows to a channel. + https://api.slack.com/methods/workflows.featured.add + """ + kwargs.update({"channel_id": channel_id}) + if isinstance(trigger_ids, (list, tuple)): + kwargs.update({"trigger_ids": ",".join(trigger_ids)}) + else: + kwargs.update({"trigger_ids": trigger_ids}) + return self.api_call("workflows.featured.add", params=kwargs) + + def workflows_featured_list( + self, + *, + channel_ids: Union[str, Sequence[str]], + **kwargs, + ) -> SlackResponse: + """List the featured workflows for specified channels. + https://api.slack.com/methods/workflows.featured.list + """ + if isinstance(channel_ids, (list, tuple)): + kwargs.update({"channel_ids": ",".join(channel_ids)}) + else: + kwargs.update({"channel_ids": channel_ids}) + return self.api_call("workflows.featured.list", params=kwargs) + + def workflows_featured_remove( + self, + *, + channel_id: str, + trigger_ids: Union[str, Sequence[str]], + **kwargs, + ) -> SlackResponse: + """Remove featured workflows from a channel. + https://api.slack.com/methods/workflows.featured.remove + """ + kwargs.update({"channel_id": channel_id}) + if isinstance(trigger_ids, (list, tuple)): + kwargs.update({"trigger_ids": ",".join(trigger_ids)}) + else: + kwargs.update({"trigger_ids": trigger_ids}) + return self.api_call("workflows.featured.remove", params=kwargs) + + def workflows_featured_set( + self, + *, + channel_id: str, + trigger_ids: Union[str, Sequence[str]], + **kwargs, + ) -> SlackResponse: + """Set featured workflows for a channel. + https://api.slack.com/methods/workflows.featured.set + """ + kwargs.update({"channel_id": channel_id}) + if isinstance(trigger_ids, (list, tuple)): + kwargs.update({"trigger_ids": ",".join(trigger_ids)}) + else: + kwargs.update({"trigger_ids": trigger_ids}) + return self.api_call("workflows.featured.set", params=kwargs) + def workflows_stepCompleted( self, *, @@ -8019,7 +8165,7 @@

Methods

https://api.slack.com/methods/admin.users.invite

-def admin_users_list(self,
*,
team_id: str,
include_deactivated_user_workspaces: bool | None = None,
is_active: bool | None = None,
cursor: str | None = None,
limit: int | None = None,
**kwargs) ‑> SlackResponse
+def admin_users_list(self,
*,
team_id: str | None = None,
include_deactivated_user_workspaces: bool | None = None,
is_active: bool | None = None,
cursor: str | None = None,
limit: int | None = None,
**kwargs) ‑> SlackResponse
@@ -8029,7 +8175,7 @@

Methods

def admin_users_list(
     self,
     *,
-    team_id: str,
+    team_id: Optional[str] = None,
     include_deactivated_user_workspaces: Optional[bool] = None,
     is_active: Optional[bool] = None,
     cursor: Optional[str] = None,
@@ -8816,7 +8962,7 @@ 

Methods

https://api.slack.com/methods/apps.uninstall

-def assistant_threads_setStatus(self, *, channel_id: str, thread_ts: str, status: str, **kwargs) ‑> SlackResponse +def assistant_threads_setStatus(self,
*,
channel_id: str,
thread_ts: str,
status: str,
loading_messages: List[str] | None = None,
**kwargs) ‑> SlackResponse
@@ -8829,15 +8975,18 @@

Methods

channel_id: str, thread_ts: str, status: str, + loading_messages: Optional[List[str]] = None, **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus """ - kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "status": status}) + kwargs.update( + {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} + ) return self.api_call("assistant.threads.setStatus", params=kwargs)
-

Revokes a token. +

Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus

@@ -8857,7 +9006,7 @@

Methods

prompts: List[Dict[str, str]], **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set suggested prompts for the given assistant thread. https://api.slack.com/methods/assistant.threads.setSuggestedPrompts """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "prompts": prompts}) @@ -8865,7 +9014,7 @@

Methods

kwargs.update({"title": title}) return self.api_call("assistant.threads.setSuggestedPrompts", json=kwargs)
-

Revokes a token. +

Set suggested prompts for the given assistant thread. https://api.slack.com/methods/assistant.threads.setSuggestedPrompts

@@ -8884,13 +9033,13 @@

Methods

title: str, **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set the title for the given assistant thread. https://api.slack.com/methods/assistant.threads.setTitle """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "title": title}) return self.api_call("assistant.threads.setTitle", params=kwargs)
-

Revokes a token. +

Set the title for the given assistant thread. https://api.slack.com/methods/assistant.threads.setTitle

@@ -9761,6 +9910,37 @@

Methods

Unarchives a channel.

+
+def chat_appendStream(self, *, channel: str, ts: str, markdown_text: str, **kwargs) ‑> SlackResponse +
+
+
+ +Expand source code + +
def chat_appendStream(
+    self,
+    *,
+    channel: str,
+    ts: str,
+    markdown_text: str,
+    **kwargs,
+) -> SlackResponse:
+    """Appends text to an existing streaming conversation.
+    https://api.slack.com/methods/chat.appendStream
+    """
+    kwargs.update(
+        {
+            "channel": channel,
+            "ts": ts,
+            "markdown_text": markdown_text,
+        }
+    )
+    return self.api_call("chat.appendStream", params=kwargs)
+
+

Appends text to an existing streaming conversation. +https://api.slack.com/methods/chat.appendStream

+
def chat_delete(self, *, channel: str, ts: str, as_user: bool | None = None, **kwargs) ‑> SlackResponse
@@ -9866,7 +10046,7 @@

Methods

https://api.slack.com/methods/chat.meMessage

-def chat_postEphemeral(self,
*,
channel: str,
user: str,
text: str | None = None,
as_user: bool | None = None,
attachments: str | Sequence[Dict | Attachment] | None = None,
blocks: str | Sequence[Dict | Block] | None = None,
thread_ts: str | None = None,
icon_emoji: str | None = None,
icon_url: str | None = None,
link_names: bool | None = None,
username: str | None = None,
parse: str | None = None,
**kwargs) ‑> SlackResponse
+def chat_postEphemeral(self,
*,
channel: str,
user: str,
text: str | None = None,
as_user: bool | None = None,
attachments: str | Sequence[Dict | Attachment] | None = None,
blocks: str | Sequence[Dict | Block] | None = None,
thread_ts: str | None = None,
icon_emoji: str | None = None,
icon_url: str | None = None,
link_names: bool | None = None,
username: str | None = None,
parse: str | None = None,
markdown_text: str | None = None,
**kwargs) ‑> SlackResponse
@@ -9888,6 +10068,7 @@

Methods

link_names: Optional[bool] = None, username: Optional[str] = None, parse: Optional[str] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Sends an ephemeral message to a user in a channel. @@ -9907,11 +10088,12 @@

Methods

"link_names": link_names, "username": username, "parse": parse, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postEphemeral", kwargs) + _warn_if_message_text_content_is_missing("chat.postEphemeral", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.postEphemeral", json=kwargs)
@@ -9919,7 +10101,7 @@

Methods

https://api.slack.com/methods/chat.postEphemeral

-def chat_postMessage(self,
*,
channel: str,
text: str | None = None,
as_user: bool | None = None,
attachments: str | Sequence[Dict | Attachment] | None = None,
blocks: str | Sequence[Dict | Block] | None = None,
thread_ts: str | None = None,
reply_broadcast: bool | None = None,
unfurl_links: bool | None = None,
unfurl_media: bool | None = None,
container_id: str | None = None,
icon_emoji: str | None = None,
icon_url: str | None = None,
mrkdwn: bool | None = None,
link_names: bool | None = None,
username: str | None = None,
parse: str | None = None,
metadata: Dict | Metadata | None = None,
**kwargs) ‑> SlackResponse
+def chat_postMessage(self,
*,
channel: str,
text: str | None = None,
as_user: bool | None = None,
attachments: str | Sequence[Dict | Attachment] | None = None,
blocks: str | Sequence[Dict | Block] | None = None,
thread_ts: str | None = None,
reply_broadcast: bool | None = None,
unfurl_links: bool | None = None,
unfurl_media: bool | None = None,
container_id: str | None = None,
icon_emoji: str | None = None,
icon_url: str | None = None,
mrkdwn: bool | None = None,
link_names: bool | None = None,
username: str | None = None,
parse: str | None = None,
metadata: Dict | Metadata | None = None,
markdown_text: str | None = None,
**kwargs) ‑> SlackResponse
@@ -9946,6 +10128,7 @@

Methods

username: Optional[str] = None, parse: Optional[str] = None, # none, full metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Sends a message to a channel. @@ -9970,11 +10153,12 @@

Methods

"username": username, "parse": parse, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.postMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.postMessage", json=kwargs)
@@ -9982,7 +10166,7 @@

Methods

https://api.slack.com/methods/chat.postMessage

-def chat_scheduleMessage(self,
*,
channel: str,
post_at: str | int,
text: str,
as_user: bool | None = None,
attachments: str | Sequence[Dict | Attachment] | None = None,
blocks: str | Sequence[Dict | Block] | None = None,
thread_ts: str | None = None,
parse: str | None = None,
reply_broadcast: bool | None = None,
unfurl_links: bool | None = None,
unfurl_media: bool | None = None,
link_names: bool | None = None,
metadata: Dict | Metadata | None = None,
**kwargs) ‑> SlackResponse
+def chat_scheduleMessage(self,
*,
channel: str,
post_at: str | int,
text: str | None = None,
as_user: bool | None = None,
attachments: str | Sequence[Dict | Attachment] | None = None,
blocks: str | Sequence[Dict | Block] | None = None,
thread_ts: str | None = None,
parse: str | None = None,
reply_broadcast: bool | None = None,
unfurl_links: bool | None = None,
unfurl_media: bool | None = None,
link_names: bool | None = None,
metadata: Dict | Metadata | None = None,
markdown_text: str | None = None,
**kwargs) ‑> SlackResponse
@@ -9994,7 +10178,7 @@

Methods

*, channel: str, post_at: Union[str, int], - text: str, + text: Optional[str] = None, as_user: Optional[bool] = None, attachments: Optional[Union[str, Sequence[Union[Dict, Attachment]]]] = None, blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, @@ -10005,6 +10189,7 @@

Methods

unfurl_media: Optional[bool] = None, link_names: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Schedules a message. @@ -10025,11 +10210,12 @@

Methods

"unfurl_media": unfurl_media, "link_names": link_names, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.scheduleMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.scheduleMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.scheduleMessage", json=kwargs)
@@ -10073,6 +10259,77 @@

Methods

+
+def chat_startStream(self,
*,
channel: str,
thread_ts: str | None = None,
markdown_text: str | None = None,
unfurl_links: bool | None = None,
unfurl_media: bool | None = None,
**kwargs) ‑> SlackResponse
+
+
+
+ +Expand source code + +
def chat_startStream(
+    self,
+    *,
+    channel: str,
+    thread_ts: Optional[str] = None,
+    markdown_text: Optional[str] = None,
+    unfurl_links: Optional[bool] = None,
+    unfurl_media: Optional[bool] = None,
+    **kwargs,
+) -> SlackResponse:
+    """Starts a new streaming conversation.
+    https://api.slack.com/methods/chat.startStream
+    """
+    kwargs.update(
+        {
+            "channel": channel,
+            "thread_ts": thread_ts,
+            "markdown_text": markdown_text,
+            "unfurl_links": unfurl_links,
+            "unfurl_media": unfurl_media,
+        }
+    )
+    return self.api_call("chat.startStream", params=kwargs)
+
+

Starts a new streaming conversation. +https://api.slack.com/methods/chat.startStream

+
+
+def chat_stopStream(self,
*,
channel: str,
ts: str,
markdown_text: str | None = None,
blocks: str | Sequence[Dict | Block] | None = None,
metadata: Dict | Metadata | None = None,
**kwargs) ‑> SlackResponse
+
+
+
+ +Expand source code + +
def chat_stopStream(
+    self,
+    *,
+    channel: str,
+    ts: str,
+    markdown_text: Optional[str] = None,
+    blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None,
+    metadata: Optional[Union[Dict, Metadata]] = None,
+    **kwargs,
+) -> SlackResponse:
+    """Stops a streaming conversation.
+    https://api.slack.com/methods/chat.stopStream
+    """
+    kwargs.update(
+        {
+            "channel": channel,
+            "ts": ts,
+            "markdown_text": markdown_text,
+            "blocks": blocks,
+            "metadata": metadata,
+        }
+    )
+    _parse_web_class_objects(kwargs)
+    return self.api_call("chat.stopStream", params=kwargs)
+
+

Stops a streaming conversation. +https://api.slack.com/methods/chat.stopStream

+
def chat_unfurl(self,
*,
channel: str | None = None,
ts: str | None = None,
source: str | None = None,
unfurl_id: str | None = None,
unfurls: Dict[str, Dict] | None = None,
user_auth_blocks: str | Sequence[Dict | Block] | None = None,
user_auth_message: str | None = None,
user_auth_required: bool | None = None,
user_auth_url: str | None = None,
**kwargs) ‑> SlackResponse
@@ -10120,7 +10377,7 @@

Methods

https://api.slack.com/methods/chat.unfurl

-def chat_update(self,
*,
channel: str,
ts: str,
text: str | None = None,
attachments: str | Sequence[Dict | Attachment] | None = None,
blocks: str | Sequence[Dict | Block] | None = None,
as_user: bool | None = None,
file_ids: str | Sequence[str] | None = None,
link_names: bool | None = None,
parse: str | None = None,
reply_broadcast: bool | None = None,
metadata: Dict | Metadata | None = None,
**kwargs) ‑> SlackResponse
+def chat_update(self,
*,
channel: str,
ts: str,
text: str | None = None,
attachments: str | Sequence[Dict | Attachment] | None = None,
blocks: str | Sequence[Dict | Block] | None = None,
as_user: bool | None = None,
file_ids: str | Sequence[str] | None = None,
link_names: bool | None = None,
parse: str | None = None,
reply_broadcast: bool | None = None,
metadata: Dict | Metadata | None = None,
markdown_text: str | None = None,
**kwargs) ‑> SlackResponse
@@ -10141,6 +10398,7 @@

Methods

parse: Optional[str] = None, # none, full reply_broadcast: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Updates a message in a channel. @@ -10158,6 +10416,7 @@

Methods

"parse": parse, "reply_broadcast": reply_broadcast, "metadata": metadata, + "markdown_text": markdown_text, } ) if isinstance(file_ids, (list, tuple)): @@ -10166,7 +10425,7 @@

Methods

kwargs.update({"file_ids": file_ids}) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.update", kwargs) + _warn_if_message_text_content_is_missing("chat.update", kwargs) # NOTE: intentionally using json over params for API methods using blocks/attachments return self.api_call("chat.update", json=kwargs)
@@ -14194,6 +14453,116 @@

Methods

to learn more about updating views and avoiding race conditions with the hash argument. https://api.slack.com/methods/views.update

+ +
+
+ +Expand source code + +
def workflows_featured_add(
+    self,
+    *,
+    channel_id: str,
+    trigger_ids: Union[str, Sequence[str]],
+    **kwargs,
+) -> SlackResponse:
+    """Add featured workflows to a channel.
+    https://api.slack.com/methods/workflows.featured.add
+    """
+    kwargs.update({"channel_id": channel_id})
+    if isinstance(trigger_ids, (list, tuple)):
+        kwargs.update({"trigger_ids": ",".join(trigger_ids)})
+    else:
+        kwargs.update({"trigger_ids": trigger_ids})
+    return self.api_call("workflows.featured.add", params=kwargs)
+
+

Add featured workflows to a channel. +https://api.slack.com/methods/workflows.featured.add

+
+ +
+
+ +Expand source code + +
def workflows_featured_list(
+    self,
+    *,
+    channel_ids: Union[str, Sequence[str]],
+    **kwargs,
+) -> SlackResponse:
+    """List the featured workflows for specified channels.
+    https://api.slack.com/methods/workflows.featured.list
+    """
+    if isinstance(channel_ids, (list, tuple)):
+        kwargs.update({"channel_ids": ",".join(channel_ids)})
+    else:
+        kwargs.update({"channel_ids": channel_ids})
+    return self.api_call("workflows.featured.list", params=kwargs)
+
+

List the featured workflows for specified channels. +https://api.slack.com/methods/workflows.featured.list

+
+ +
+
+ +Expand source code + +
def workflows_featured_remove(
+    self,
+    *,
+    channel_id: str,
+    trigger_ids: Union[str, Sequence[str]],
+    **kwargs,
+) -> SlackResponse:
+    """Remove featured workflows from a channel.
+    https://api.slack.com/methods/workflows.featured.remove
+    """
+    kwargs.update({"channel_id": channel_id})
+    if isinstance(trigger_ids, (list, tuple)):
+        kwargs.update({"trigger_ids": ",".join(trigger_ids)})
+    else:
+        kwargs.update({"trigger_ids": trigger_ids})
+    return self.api_call("workflows.featured.remove", params=kwargs)
+
+

Remove featured workflows from a channel. +https://api.slack.com/methods/workflows.featured.remove

+
+ +
+
+ +Expand source code + +
def workflows_featured_set(
+    self,
+    *,
+    channel_id: str,
+    trigger_ids: Union[str, Sequence[str]],
+    **kwargs,
+) -> SlackResponse:
+    """Set featured workflows for a channel.
+    https://api.slack.com/methods/workflows.featured.set
+    """
+    kwargs.update({"channel_id": channel_id})
+    if isinstance(trigger_ids, (list, tuple)):
+        kwargs.update({"trigger_ids": ",".join(trigger_ids)})
+    else:
+        kwargs.update({"trigger_ids": trigger_ids})
+    return self.api_call("workflows.featured.set", params=kwargs)
+
+

Set featured workflows for a channel. +https://api.slack.com/methods/workflows.featured.set

+
def workflows_stepCompleted(self, *, workflow_step_execute_id: str, outputs: dict | None = None, **kwargs) ‑> SlackResponse
@@ -14554,13 +14923,13 @@

Inherited members

http_resp = opener.open(req, timeout=self.timeout) else: http_resp = urlopen(req, context=self.ssl, timeout=self.timeout) - charset: str = http_resp.headers.get_content_charset() or "utf-8" # type: ignore[union-attr] - response_body: str = http_resp.read().decode(charset) # type: ignore[union-attr] + charset: str = http_resp.headers.get_content_charset() or "utf-8" + response_body: str = http_resp.read().decode(charset) resp = WebhookResponse( url=url, - status_code=http_resp.status, # type: ignore[union-attr] + status_code=http_resp.status, body=response_body, - headers=http_resp.headers, # type: ignore[arg-type, union-attr] + headers=http_resp.headers, # type: ignore[arg-type] ) _debug_log_response(self.logger, resp) return resp @@ -14927,6 +15296,7 @@

WebClientchannels_setPurpose
  • channels_setTopic
  • channels_unarchive
  • +
  • chat_appendStream
  • chat_delete
  • chat_deleteScheduledMessage
  • chat_getPermalink
  • @@ -14935,6 +15305,8 @@

    WebClientchat_postMessage
  • chat_scheduleMessage
  • chat_scheduledMessages_list
  • +
  • chat_startStream
  • +
  • chat_stopStream
  • chat_unfurl
  • chat_update
  • conversations_acceptSharedInvite
  • @@ -15077,6 +15449,10 @@

    WebClientviews_publish
  • views_push
  • views_update
  • +
  • workflows_featured_add
  • +
  • workflows_featured_list
  • +
  • workflows_featured_remove
  • +
  • workflows_featured_set
  • workflows_stepCompleted
  • workflows_stepFailed
  • workflows_updateStep
  • diff --git a/docs/reference/models/blocks/basic_components.html b/docs/reference/models/blocks/basic_components.html index ac7ce17ac..7b56352d3 100644 --- a/docs/reference/models/blocks/basic_components.html +++ b/docs/reference/models/blocks/basic_components.html @@ -56,7 +56,7 @@

    Classes

    Expand source code
    class ConfirmObject(JsonObject):
    -    attributes = {}  # type: ignore[assignment] # no attributes because to_dict has unique implementations
    +    attributes: Set[str] = set()
     
         title_max_length = 100
         text_max_length = 300
    @@ -164,7 +164,7 @@ 

    Ancestors

    Class variables

    -
    var attributes
    +
    var attributes : Set[str]

    The type of the None singleton.

    @@ -546,7 +546,7 @@

    Inherited members

    different required formats in different situations """ - attributes = {} # type: ignore[assignment] # no attributes because to_dict has unique implementations + attributes: Set[str] = set() logger = logging.getLogger(__name__) label_max_length = 75 @@ -719,7 +719,7 @@

    Ancestors

    Class variables

    -
    var attributes
    +
    var attributes : Set[str]

    The type of the None singleton.

    @@ -828,7 +828,7 @@

    Inherited members

    different required formats in different situations """ - attributes = {} # type: ignore[assignment] # no attributes because to_dict has unique implementations + attributes: Set[str] = set() label_max_length = 75 options_max_length = 100 logger = logging.getLogger(__name__) @@ -932,7 +932,7 @@

    Ancestors

    Class variables

    -
    var attributes
    +
    var attributes : Set[str]

    The type of the None singleton.

    diff --git a/docs/reference/models/blocks/index.html b/docs/reference/models/blocks/index.html index d3327ac93..97d9b5294 100644 --- a/docs/reference/models/blocks/index.html +++ b/docs/reference/models/blocks/index.html @@ -1130,7 +1130,7 @@

    Inherited members

    Expand source code
    class ConfirmObject(JsonObject):
    -    attributes = {}  # type: ignore[assignment] # no attributes because to_dict has unique implementations
    +    attributes: Set[str] = set()
     
         title_max_length = 100
         text_max_length = 300
    @@ -1238,7 +1238,7 @@ 

    Ancestors

    Class variables

    -
    var attributes
    +
    var attributes : Set[str]

    The type of the None singleton.

    @@ -3936,7 +3936,7 @@

    Inherited members

    different required formats in different situations """ - attributes = {} # type: ignore[assignment] # no attributes because to_dict has unique implementations + attributes: Set[str] = set() logger = logging.getLogger(__name__) label_max_length = 75 @@ -4109,7 +4109,7 @@

    Ancestors

    Class variables

    -
    var attributes
    +
    var attributes : Set[str]

    The type of the None singleton.

    @@ -4218,7 +4218,7 @@

    Inherited members

    different required formats in different situations """ - attributes = {} # type: ignore[assignment] # no attributes because to_dict has unique implementations + attributes: Set[str] = set() label_max_length = 75 options_max_length = 100 logger = logging.getLogger(__name__) @@ -4322,7 +4322,7 @@

    Ancestors

    Class variables

    -
    var attributes
    +
    var attributes : Set[str]

    The type of the None singleton.

    diff --git a/docs/reference/models/dialoags.html b/docs/reference/models/dialoags.html index 2657bdbe8..d850bd9ca 100644 --- a/docs/reference/models/dialoags.html +++ b/docs/reference/models/dialoags.html @@ -247,7 +247,7 @@

    Inherited members

    Expand source code
    class DialogBuilder(JsonObject):
    -    attributes = {}  # type: ignore[assignment] # no attributes because to_dict has unique implementation
    +    attributes: Set[str] = set()
     
         _callback_id: Optional[str]
         _elements: List[Union[DialogTextComponent, AbstractDialogSelector]]
    @@ -687,7 +687,7 @@ 

    Ancestors

    Class variables

    -
    var attributes
    +
    var attributes : Set[str]

    The type of the None singleton.

    diff --git a/docs/reference/models/dialogs/index.html b/docs/reference/models/dialogs/index.html index d077673e1..85cc3757d 100644 --- a/docs/reference/models/dialogs/index.html +++ b/docs/reference/models/dialogs/index.html @@ -247,7 +247,7 @@

    Inherited members

    Expand source code
    class DialogBuilder(JsonObject):
    -    attributes = {}  # type: ignore[assignment] # no attributes because to_dict has unique implementation
    +    attributes: Set[str] = set()
     
         _callback_id: Optional[str]
         _elements: List[Union[DialogTextComponent, AbstractDialogSelector]]
    @@ -687,7 +687,7 @@ 

    Ancestors

    Class variables

    -
    var attributes
    +
    var attributes : Set[str]

    The type of the None singleton.

    diff --git a/docs/reference/oauth/installation_store/async_cacheable_installation_store.html b/docs/reference/oauth/installation_store/async_cacheable_installation_store.html index 100c62c4a..a38205174 100644 --- a/docs/reference/oauth/installation_store/async_cacheable_installation_store.html +++ b/docs/reference/oauth/installation_store/async_cacheable_installation_store.html @@ -74,7 +74,7 @@

    Classes

    def logger(self) -> Logger: return self.underlying.logger - async def async_save(self, installation: Installation): # type: ignore[explicit-override] + async def async_save(self, installation: Installation): # Invalidate cache data for update operations key = f"{installation.enterprise_id or ''}-{installation.team_id or ''}" if key in self.cached_bots: @@ -84,14 +84,14 @@

    Classes

    self.cached_installations.pop(key) return await self.underlying.async_save(installation) - async def async_save_bot(self, bot: Bot): # type: ignore[explicit-override] + async def async_save_bot(self, bot: Bot): # Invalidate cache data for update operations key = f"{bot.enterprise_id or ''}-{bot.team_id or ''}" if key in self.cached_bots: self.cached_bots.pop(key) return await self.underlying.async_save_bot(bot) - async def async_find_bot( # type: ignore[explicit-override] + async def async_find_bot( self, *, enterprise_id: Optional[str], @@ -112,7 +112,7 @@

    Classes

    self.cached_bots[key] = bot return bot - async def async_find_installation( # type: ignore[explicit-override] + async def async_find_installation( self, *, enterprise_id: Optional[str], diff --git a/docs/reference/oauth/installation_store/cacheable_installation_store.html b/docs/reference/oauth/installation_store/cacheable_installation_store.html index 5e2802f11..54bb7662d 100644 --- a/docs/reference/oauth/installation_store/cacheable_installation_store.html +++ b/docs/reference/oauth/installation_store/cacheable_installation_store.html @@ -74,7 +74,7 @@

    Classes

    def logger(self) -> Logger: return self.underlying.logger - def save(self, installation: Installation): # type: ignore[explicit-override] + def save(self, installation: Installation): # Invalidate cache data for update operations key = f"{installation.enterprise_id or ''}-{installation.team_id or ''}" if key in self.cached_bots: @@ -85,14 +85,14 @@

    Classes

    return self.underlying.save(installation) - def save_bot(self, bot: Bot): # type: ignore[explicit-override] + def save_bot(self, bot: Bot): # Invalidate cache data for update operations key = f"{bot.enterprise_id or ''}-{bot.team_id or ''}" if key in self.cached_bots: self.cached_bots.pop(key) return self.underlying.save_bot(bot) - def find_bot( # type: ignore[explicit-override] + def find_bot( self, *, enterprise_id: Optional[str], @@ -113,7 +113,7 @@

    Classes

    self.cached_bots[key] = bot return bot - def find_installation( # type: ignore[explicit-override] + def find_installation( self, *, enterprise_id: Optional[str], diff --git a/docs/reference/socket_mode/client.html b/docs/reference/socket_mode/client.html index dda047bd6..3c8c615f9 100644 --- a/docs/reference/socket_mode/client.html +++ b/docs/reference/socket_mode/client.html @@ -167,7 +167,7 @@

    Classes

    for listener in self.message_listeners: try: - listener(self, message, raw_message) # type: ignore[call-arg, arg-type] + listener(self, message, raw_message) # type: ignore[call-arg, arg-type, misc] except Exception as e: self.logger.exception(f"Failed to run a message listener: {e}") @@ -431,7 +431,7 @@

    Methods

    for listener in self.message_listeners: try: - listener(self, message, raw_message) # type: ignore[call-arg, arg-type] + listener(self, message, raw_message) # type: ignore[call-arg, arg-type, misc] except Exception as e: self.logger.exception(f"Failed to run a message listener: {e}") diff --git a/docs/reference/socket_mode/websocket_client/index.html b/docs/reference/socket_mode/websocket_client/index.html index 20a1f0ac5..6cce0c780 100644 --- a/docs/reference/socket_mode/websocket_client/index.html +++ b/docs/reference/socket_mode/websocket_client/index.html @@ -91,7 +91,7 @@

    Classes

    auto_reconnect_enabled: bool default_auto_reconnect_enabled: bool - close: bool # type: ignore[assignment] + closed: bool connect_operation_lock: Lock on_open_listeners: List[Callable[[WebSocketApp], None]] @@ -258,7 +258,7 @@

    Classes

    ) raise e - def close(self) -> None: # type: ignore[explicit-override, no-redef] + def close(self) -> None: self.closed = True self.auto_reconnect_enabled = False self.disconnect() @@ -384,7 +384,7 @@

    Methods

    Expand source code -
    def close(self) -> None:  # type: ignore[explicit-override, no-redef]
    +
    def close(self) -> None:
         self.closed = True
         self.auto_reconnect_enabled = False
         self.disconnect()
    diff --git a/docs/reference/web/async_client.html b/docs/reference/web/async_client.html
    index 86403ce5d..ab5c0ab98 100644
    --- a/docs/reference/web/async_client.html
    +++ b/docs/reference/web/async_client.html
    @@ -1752,7 +1752,7 @@ 

    Classes

    async def admin_users_list( self, *, - team_id: str, + team_id: Optional[str] = None, include_deactivated_user_workspaces: Optional[bool] = None, is_active: Optional[bool] = None, cursor: Optional[str] = None, @@ -2097,12 +2097,15 @@

    Classes

    channel_id: str, thread_ts: str, status: str, + loading_messages: Optional[List[str]] = None, **kwargs, ) -> AsyncSlackResponse: - """Revokes a token. + """Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus """ - kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "status": status}) + kwargs.update( + {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} + ) return await self.api_call("assistant.threads.setStatus", params=kwargs) async def assistant_threads_setTitle( @@ -2113,7 +2116,7 @@

    Classes

    title: str, **kwargs, ) -> AsyncSlackResponse: - """Revokes a token. + """Set the title for the given assistant thread. https://api.slack.com/methods/assistant.threads.setTitle """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "title": title}) @@ -2128,7 +2131,7 @@

    Classes

    prompts: List[Dict[str, str]], **kwargs, ) -> AsyncSlackResponse: - """Revokes a token. + """Set suggested prompts for the given assistant thread. https://api.slack.com/methods/assistant.threads.setSuggestedPrompts """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "prompts": prompts}) @@ -2642,6 +2645,26 @@

    Classes

    # -------------------------- + async def chat_appendStream( + self, + *, + channel: str, + ts: str, + markdown_text: str, + **kwargs, + ) -> AsyncSlackResponse: + """Appends text to an existing streaming conversation. + https://api.slack.com/methods/chat.appendStream + """ + kwargs.update( + { + "channel": channel, + "ts": ts, + "markdown_text": markdown_text, + } + ) + return await self.api_call("chat.appendStream", params=kwargs) + async def chat_delete( self, *, @@ -2717,6 +2740,7 @@

    Classes

    link_names: Optional[bool] = None, username: Optional[str] = None, parse: Optional[str] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> AsyncSlackResponse: """Sends an ephemeral message to a user in a channel. @@ -2736,11 +2760,12 @@

    Classes

    "link_names": link_names, "username": username, "parse": parse, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postEphemeral", kwargs) + _warn_if_message_text_content_is_missing("chat.postEphemeral", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return await self.api_call("chat.postEphemeral", json=kwargs) @@ -2764,6 +2789,7 @@

    Classes

    username: Optional[str] = None, parse: Optional[str] = None, # none, full metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> AsyncSlackResponse: """Sends a message to a channel. @@ -2788,11 +2814,12 @@

    Classes

    "username": username, "parse": parse, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.postMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return await self.api_call("chat.postMessage", json=kwargs) @@ -2801,7 +2828,7 @@

    Classes

    *, channel: str, post_at: Union[str, int], - text: str, + text: Optional[str] = None, as_user: Optional[bool] = None, attachments: Optional[Union[str, Sequence[Union[Dict, Attachment]]]] = None, blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, @@ -2812,6 +2839,7 @@

    Classes

    unfurl_media: Optional[bool] = None, link_names: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> AsyncSlackResponse: """Schedules a message. @@ -2832,14 +2860,90 @@

    Classes

    "unfurl_media": unfurl_media, "link_names": link_names, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.scheduleMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.scheduleMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return await self.api_call("chat.scheduleMessage", json=kwargs) + async def chat_scheduledMessages_list( + self, + *, + channel: Optional[str] = None, + cursor: Optional[str] = None, + latest: Optional[str] = None, + limit: Optional[int] = None, + oldest: Optional[str] = None, + team_id: Optional[str] = None, + **kwargs, + ) -> AsyncSlackResponse: + """Lists all scheduled messages. + https://api.slack.com/methods/chat.scheduledMessages.list + """ + kwargs.update( + { + "channel": channel, + "cursor": cursor, + "latest": latest, + "limit": limit, + "oldest": oldest, + "team_id": team_id, + } + ) + return await self.api_call("chat.scheduledMessages.list", params=kwargs) + + async def chat_startStream( + self, + *, + channel: str, + thread_ts: Optional[str] = None, + markdown_text: Optional[str] = None, + unfurl_links: Optional[bool] = None, + unfurl_media: Optional[bool] = None, + **kwargs, + ) -> AsyncSlackResponse: + """Starts a new streaming conversation. + https://api.slack.com/methods/chat.startStream + """ + kwargs.update( + { + "channel": channel, + "thread_ts": thread_ts, + "markdown_text": markdown_text, + "unfurl_links": unfurl_links, + "unfurl_media": unfurl_media, + } + ) + return await self.api_call("chat.startStream", params=kwargs) + + async def chat_stopStream( + self, + *, + channel: str, + ts: str, + markdown_text: Optional[str] = None, + blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, + metadata: Optional[Union[Dict, Metadata]] = None, + **kwargs, + ) -> AsyncSlackResponse: + """Stops a streaming conversation. + https://api.slack.com/methods/chat.stopStream + """ + kwargs.update( + { + "channel": channel, + "ts": ts, + "markdown_text": markdown_text, + "blocks": blocks, + "metadata": metadata, + } + ) + _parse_web_class_objects(kwargs) + return await self.api_call("chat.stopStream", params=kwargs) + async def chat_unfurl( self, *, @@ -2889,6 +2993,7 @@

    Classes

    parse: Optional[str] = None, # none, full reply_broadcast: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> AsyncSlackResponse: """Updates a message in a channel. @@ -2906,6 +3011,7 @@

    Classes

    "parse": parse, "reply_broadcast": reply_broadcast, "metadata": metadata, + "markdown_text": markdown_text, } ) if isinstance(file_ids, (list, tuple)): @@ -2914,36 +3020,10 @@

    Classes

    kwargs.update({"file_ids": file_ids}) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.update", kwargs) + _warn_if_message_text_content_is_missing("chat.update", kwargs) # NOTE: intentionally using json over params for API methods using blocks/attachments return await self.api_call("chat.update", json=kwargs) - async def chat_scheduledMessages_list( - self, - *, - channel: Optional[str] = None, - cursor: Optional[str] = None, - latest: Optional[str] = None, - limit: Optional[int] = None, - oldest: Optional[str] = None, - team_id: Optional[str] = None, - **kwargs, - ) -> AsyncSlackResponse: - """Lists all scheduled messages. - https://api.slack.com/methods/chat.scheduledMessages.list - """ - kwargs.update( - { - "channel": channel, - "cursor": cursor, - "latest": latest, - "limit": limit, - "oldest": oldest, - "team_id": team_id, - } - ) - return await self.api_call("chat.scheduledMessages.list", params=kwargs) - async def conversations_acceptSharedInvite( self, *, @@ -5438,6 +5518,72 @@

    Classes

    # NOTE: Intentionally using json for the "view" parameter return await self.api_call("views.publish", json=kwargs) + async def workflows_featured_add( + self, + *, + channel_id: str, + trigger_ids: Union[str, Sequence[str]], + **kwargs, + ) -> AsyncSlackResponse: + """Add featured workflows to a channel. + https://api.slack.com/methods/workflows.featured.add + """ + kwargs.update({"channel_id": channel_id}) + if isinstance(trigger_ids, (list, tuple)): + kwargs.update({"trigger_ids": ",".join(trigger_ids)}) + else: + kwargs.update({"trigger_ids": trigger_ids}) + return await self.api_call("workflows.featured.add", params=kwargs) + + async def workflows_featured_list( + self, + *, + channel_ids: Union[str, Sequence[str]], + **kwargs, + ) -> AsyncSlackResponse: + """List the featured workflows for specified channels. + https://api.slack.com/methods/workflows.featured.list + """ + if isinstance(channel_ids, (list, tuple)): + kwargs.update({"channel_ids": ",".join(channel_ids)}) + else: + kwargs.update({"channel_ids": channel_ids}) + return await self.api_call("workflows.featured.list", params=kwargs) + + async def workflows_featured_remove( + self, + *, + channel_id: str, + trigger_ids: Union[str, Sequence[str]], + **kwargs, + ) -> AsyncSlackResponse: + """Remove featured workflows from a channel. + https://api.slack.com/methods/workflows.featured.remove + """ + kwargs.update({"channel_id": channel_id}) + if isinstance(trigger_ids, (list, tuple)): + kwargs.update({"trigger_ids": ",".join(trigger_ids)}) + else: + kwargs.update({"trigger_ids": trigger_ids}) + return await self.api_call("workflows.featured.remove", params=kwargs) + + async def workflows_featured_set( + self, + *, + channel_id: str, + trigger_ids: Union[str, Sequence[str]], + **kwargs, + ) -> AsyncSlackResponse: + """Set featured workflows for a channel. + https://api.slack.com/methods/workflows.featured.set + """ + kwargs.update({"channel_id": channel_id}) + if isinstance(trigger_ids, (list, tuple)): + kwargs.update({"trigger_ids": ",".join(trigger_ids)}) + else: + kwargs.update({"trigger_ids": trigger_ids}) + return await self.api_call("workflows.featured.set", params=kwargs) + async def workflows_stepCompleted( self, *, @@ -7915,7 +8061,7 @@

    Methods

    https://api.slack.com/methods/admin.users.invite

    -async def admin_users_list(self,
    *,
    team_id: str,
    include_deactivated_user_workspaces: bool | None = None,
    is_active: bool | None = None,
    cursor: str | None = None,
    limit: int | None = None,
    **kwargs) ‑> AsyncSlackResponse
    +async def admin_users_list(self,
    *,
    team_id: str | None = None,
    include_deactivated_user_workspaces: bool | None = None,
    is_active: bool | None = None,
    cursor: str | None = None,
    limit: int | None = None,
    **kwargs) ‑> AsyncSlackResponse
    @@ -7925,7 +8071,7 @@

    Methods

    async def admin_users_list(
         self,
         *,
    -    team_id: str,
    +    team_id: Optional[str] = None,
         include_deactivated_user_workspaces: Optional[bool] = None,
         is_active: Optional[bool] = None,
         cursor: Optional[str] = None,
    @@ -8712,7 +8858,7 @@ 

    Methods

    https://api.slack.com/methods/apps.uninstall

    -async def assistant_threads_setStatus(self, *, channel_id: str, thread_ts: str, status: str, **kwargs) ‑> AsyncSlackResponse +async def assistant_threads_setStatus(self,
    *,
    channel_id: str,
    thread_ts: str,
    status: str,
    loading_messages: List[str] | None = None,
    **kwargs) ‑> AsyncSlackResponse
    @@ -8725,15 +8871,18 @@

    Methods

    channel_id: str, thread_ts: str, status: str, + loading_messages: Optional[List[str]] = None, **kwargs, ) -> AsyncSlackResponse: - """Revokes a token. + """Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus """ - kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "status": status}) + kwargs.update( + {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} + ) return await self.api_call("assistant.threads.setStatus", params=kwargs)
    -

    Revokes a token. +

    Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus

    @@ -8753,7 +8902,7 @@

    Methods

    prompts: List[Dict[str, str]], **kwargs, ) -> AsyncSlackResponse: - """Revokes a token. + """Set suggested prompts for the given assistant thread. https://api.slack.com/methods/assistant.threads.setSuggestedPrompts """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "prompts": prompts}) @@ -8761,7 +8910,7 @@

    Methods

    kwargs.update({"title": title}) return await self.api_call("assistant.threads.setSuggestedPrompts", json=kwargs)
    -

    Revokes a token. +

    Set suggested prompts for the given assistant thread. https://api.slack.com/methods/assistant.threads.setSuggestedPrompts

    @@ -8780,13 +8929,13 @@

    Methods

    title: str, **kwargs, ) -> AsyncSlackResponse: - """Revokes a token. + """Set the title for the given assistant thread. https://api.slack.com/methods/assistant.threads.setTitle """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "title": title}) return await self.api_call("assistant.threads.setTitle", params=kwargs)
    -

    Revokes a token. +

    Set the title for the given assistant thread. https://api.slack.com/methods/assistant.threads.setTitle

    @@ -9657,6 +9806,37 @@

    Methods

    Unarchives a channel.

    +
    +async def chat_appendStream(self, *, channel: str, ts: str, markdown_text: str, **kwargs) ‑> AsyncSlackResponse +
    +
    +
    + +Expand source code + +
    async def chat_appendStream(
    +    self,
    +    *,
    +    channel: str,
    +    ts: str,
    +    markdown_text: str,
    +    **kwargs,
    +) -> AsyncSlackResponse:
    +    """Appends text to an existing streaming conversation.
    +    https://api.slack.com/methods/chat.appendStream
    +    """
    +    kwargs.update(
    +        {
    +            "channel": channel,
    +            "ts": ts,
    +            "markdown_text": markdown_text,
    +        }
    +    )
    +    return await self.api_call("chat.appendStream", params=kwargs)
    +
    +

    Appends text to an existing streaming conversation. +https://api.slack.com/methods/chat.appendStream

    +
    async def chat_delete(self, *, channel: str, ts: str, as_user: bool | None = None, **kwargs) ‑> AsyncSlackResponse
    @@ -9762,7 +9942,7 @@

    Methods

    https://api.slack.com/methods/chat.meMessage

    -async def chat_postEphemeral(self,
    *,
    channel: str,
    user: str,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    icon_emoji: str | None = None,
    icon_url: str | None = None,
    link_names: bool | None = None,
    username: str | None = None,
    parse: str | None = None,
    **kwargs) ‑> AsyncSlackResponse
    +async def chat_postEphemeral(self,
    *,
    channel: str,
    user: str,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    icon_emoji: str | None = None,
    icon_url: str | None = None,
    link_names: bool | None = None,
    username: str | None = None,
    parse: str | None = None,
    markdown_text: str | None = None,
    **kwargs) ‑> AsyncSlackResponse
    @@ -9784,6 +9964,7 @@

    Methods

    link_names: Optional[bool] = None, username: Optional[str] = None, parse: Optional[str] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> AsyncSlackResponse: """Sends an ephemeral message to a user in a channel. @@ -9803,11 +9984,12 @@

    Methods

    "link_names": link_names, "username": username, "parse": parse, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postEphemeral", kwargs) + _warn_if_message_text_content_is_missing("chat.postEphemeral", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return await self.api_call("chat.postEphemeral", json=kwargs)
    @@ -9815,7 +9997,7 @@

    Methods

    https://api.slack.com/methods/chat.postEphemeral

    -async def chat_postMessage(self,
    *,
    channel: str,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    reply_broadcast: bool | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    container_id: str | None = None,
    icon_emoji: str | None = None,
    icon_url: str | None = None,
    mrkdwn: bool | None = None,
    link_names: bool | None = None,
    username: str | None = None,
    parse: str | None = None,
    metadata: Dict | Metadata | None = None,
    **kwargs) ‑> AsyncSlackResponse
    +async def chat_postMessage(self,
    *,
    channel: str,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    reply_broadcast: bool | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    container_id: str | None = None,
    icon_emoji: str | None = None,
    icon_url: str | None = None,
    mrkdwn: bool | None = None,
    link_names: bool | None = None,
    username: str | None = None,
    parse: str | None = None,
    metadata: Dict | Metadata | None = None,
    markdown_text: str | None = None,
    **kwargs) ‑> AsyncSlackResponse
    @@ -9842,6 +10024,7 @@

    Methods

    username: Optional[str] = None, parse: Optional[str] = None, # none, full metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> AsyncSlackResponse: """Sends a message to a channel. @@ -9866,11 +10049,12 @@

    Methods

    "username": username, "parse": parse, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.postMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return await self.api_call("chat.postMessage", json=kwargs)
    @@ -9878,7 +10062,7 @@

    Methods

    https://api.slack.com/methods/chat.postMessage

    -async def chat_scheduleMessage(self,
    *,
    channel: str,
    post_at: str | int,
    text: str,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    parse: str | None = None,
    reply_broadcast: bool | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    link_names: bool | None = None,
    metadata: Dict | Metadata | None = None,
    **kwargs) ‑> AsyncSlackResponse
    +async def chat_scheduleMessage(self,
    *,
    channel: str,
    post_at: str | int,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    parse: str | None = None,
    reply_broadcast: bool | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    link_names: bool | None = None,
    metadata: Dict | Metadata | None = None,
    markdown_text: str | None = None,
    **kwargs) ‑> AsyncSlackResponse
    @@ -9890,7 +10074,7 @@

    Methods

    *, channel: str, post_at: Union[str, int], - text: str, + text: Optional[str] = None, as_user: Optional[bool] = None, attachments: Optional[Union[str, Sequence[Union[Dict, Attachment]]]] = None, blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, @@ -9901,6 +10085,7 @@

    Methods

    unfurl_media: Optional[bool] = None, link_names: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> AsyncSlackResponse: """Schedules a message. @@ -9921,11 +10106,12 @@

    Methods

    "unfurl_media": unfurl_media, "link_names": link_names, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.scheduleMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.scheduleMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return await self.api_call("chat.scheduleMessage", json=kwargs)
    @@ -9969,6 +10155,77 @@

    Methods

    +
    +async def chat_startStream(self,
    *,
    channel: str,
    thread_ts: str | None = None,
    markdown_text: str | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    **kwargs) ‑> AsyncSlackResponse
    +
    +
    +
    + +Expand source code + +
    async def chat_startStream(
    +    self,
    +    *,
    +    channel: str,
    +    thread_ts: Optional[str] = None,
    +    markdown_text: Optional[str] = None,
    +    unfurl_links: Optional[bool] = None,
    +    unfurl_media: Optional[bool] = None,
    +    **kwargs,
    +) -> AsyncSlackResponse:
    +    """Starts a new streaming conversation.
    +    https://api.slack.com/methods/chat.startStream
    +    """
    +    kwargs.update(
    +        {
    +            "channel": channel,
    +            "thread_ts": thread_ts,
    +            "markdown_text": markdown_text,
    +            "unfurl_links": unfurl_links,
    +            "unfurl_media": unfurl_media,
    +        }
    +    )
    +    return await self.api_call("chat.startStream", params=kwargs)
    +
    +

    Starts a new streaming conversation. +https://api.slack.com/methods/chat.startStream

    +
    +
    +async def chat_stopStream(self,
    *,
    channel: str,
    ts: str,
    markdown_text: str | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    metadata: Dict | Metadata | None = None,
    **kwargs) ‑> AsyncSlackResponse
    +
    +
    +
    + +Expand source code + +
    async def chat_stopStream(
    +    self,
    +    *,
    +    channel: str,
    +    ts: str,
    +    markdown_text: Optional[str] = None,
    +    blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None,
    +    metadata: Optional[Union[Dict, Metadata]] = None,
    +    **kwargs,
    +) -> AsyncSlackResponse:
    +    """Stops a streaming conversation.
    +    https://api.slack.com/methods/chat.stopStream
    +    """
    +    kwargs.update(
    +        {
    +            "channel": channel,
    +            "ts": ts,
    +            "markdown_text": markdown_text,
    +            "blocks": blocks,
    +            "metadata": metadata,
    +        }
    +    )
    +    _parse_web_class_objects(kwargs)
    +    return await self.api_call("chat.stopStream", params=kwargs)
    +
    +

    Stops a streaming conversation. +https://api.slack.com/methods/chat.stopStream

    +
    async def chat_unfurl(self,
    *,
    channel: str | None = None,
    ts: str | None = None,
    source: str | None = None,
    unfurl_id: str | None = None,
    unfurls: Dict[str, Dict] | None = None,
    user_auth_blocks: str | Sequence[Dict | Block] | None = None,
    user_auth_message: str | None = None,
    user_auth_required: bool | None = None,
    user_auth_url: str | None = None,
    **kwargs) ‑> AsyncSlackResponse
    @@ -10016,7 +10273,7 @@

    Methods

    https://api.slack.com/methods/chat.unfurl

    -async def chat_update(self,
    *,
    channel: str,
    ts: str,
    text: str | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    as_user: bool | None = None,
    file_ids: str | Sequence[str] | None = None,
    link_names: bool | None = None,
    parse: str | None = None,
    reply_broadcast: bool | None = None,
    metadata: Dict | Metadata | None = None,
    **kwargs) ‑> AsyncSlackResponse
    +async def chat_update(self,
    *,
    channel: str,
    ts: str,
    text: str | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    as_user: bool | None = None,
    file_ids: str | Sequence[str] | None = None,
    link_names: bool | None = None,
    parse: str | None = None,
    reply_broadcast: bool | None = None,
    metadata: Dict | Metadata | None = None,
    markdown_text: str | None = None,
    **kwargs) ‑> AsyncSlackResponse
    @@ -10037,6 +10294,7 @@

    Methods

    parse: Optional[str] = None, # none, full reply_broadcast: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> AsyncSlackResponse: """Updates a message in a channel. @@ -10054,6 +10312,7 @@

    Methods

    "parse": parse, "reply_broadcast": reply_broadcast, "metadata": metadata, + "markdown_text": markdown_text, } ) if isinstance(file_ids, (list, tuple)): @@ -10062,7 +10321,7 @@

    Methods

    kwargs.update({"file_ids": file_ids}) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.update", kwargs) + _warn_if_message_text_content_is_missing("chat.update", kwargs) # NOTE: intentionally using json over params for API methods using blocks/attachments return await self.api_call("chat.update", json=kwargs)
    @@ -14090,6 +14349,116 @@

    Methods

    to learn more about updating views and avoiding race conditions with the hash argument. https://api.slack.com/methods/views.update

    + +
    +
    + +Expand source code + +
    async def workflows_featured_add(
    +    self,
    +    *,
    +    channel_id: str,
    +    trigger_ids: Union[str, Sequence[str]],
    +    **kwargs,
    +) -> AsyncSlackResponse:
    +    """Add featured workflows to a channel.
    +    https://api.slack.com/methods/workflows.featured.add
    +    """
    +    kwargs.update({"channel_id": channel_id})
    +    if isinstance(trigger_ids, (list, tuple)):
    +        kwargs.update({"trigger_ids": ",".join(trigger_ids)})
    +    else:
    +        kwargs.update({"trigger_ids": trigger_ids})
    +    return await self.api_call("workflows.featured.add", params=kwargs)
    +
    +

    Add featured workflows to a channel. +https://api.slack.com/methods/workflows.featured.add

    +
    + +
    +
    + +Expand source code + +
    async def workflows_featured_list(
    +    self,
    +    *,
    +    channel_ids: Union[str, Sequence[str]],
    +    **kwargs,
    +) -> AsyncSlackResponse:
    +    """List the featured workflows for specified channels.
    +    https://api.slack.com/methods/workflows.featured.list
    +    """
    +    if isinstance(channel_ids, (list, tuple)):
    +        kwargs.update({"channel_ids": ",".join(channel_ids)})
    +    else:
    +        kwargs.update({"channel_ids": channel_ids})
    +    return await self.api_call("workflows.featured.list", params=kwargs)
    +
    +

    List the featured workflows for specified channels. +https://api.slack.com/methods/workflows.featured.list

    +
    + +
    +
    + +Expand source code + +
    async def workflows_featured_remove(
    +    self,
    +    *,
    +    channel_id: str,
    +    trigger_ids: Union[str, Sequence[str]],
    +    **kwargs,
    +) -> AsyncSlackResponse:
    +    """Remove featured workflows from a channel.
    +    https://api.slack.com/methods/workflows.featured.remove
    +    """
    +    kwargs.update({"channel_id": channel_id})
    +    if isinstance(trigger_ids, (list, tuple)):
    +        kwargs.update({"trigger_ids": ",".join(trigger_ids)})
    +    else:
    +        kwargs.update({"trigger_ids": trigger_ids})
    +    return await self.api_call("workflows.featured.remove", params=kwargs)
    +
    +

    Remove featured workflows from a channel. +https://api.slack.com/methods/workflows.featured.remove

    +
    + +
    +
    + +Expand source code + +
    async def workflows_featured_set(
    +    self,
    +    *,
    +    channel_id: str,
    +    trigger_ids: Union[str, Sequence[str]],
    +    **kwargs,
    +) -> AsyncSlackResponse:
    +    """Set featured workflows for a channel.
    +    https://api.slack.com/methods/workflows.featured.set
    +    """
    +    kwargs.update({"channel_id": channel_id})
    +    if isinstance(trigger_ids, (list, tuple)):
    +        kwargs.update({"trigger_ids": ",".join(trigger_ids)})
    +    else:
    +        kwargs.update({"trigger_ids": trigger_ids})
    +    return await self.api_call("workflows.featured.set", params=kwargs)
    +
    +

    Set featured workflows for a channel. +https://api.slack.com/methods/workflows.featured.set

    +
    async def workflows_stepCompleted(self, *, workflow_step_execute_id: str, outputs: dict | None = None, **kwargs) ‑> AsyncSlackResponse
    @@ -14363,6 +14732,7 @@

    channels_setPurpose
  • channels_setTopic
  • channels_unarchive
  • +
  • chat_appendStream
  • chat_delete
  • chat_deleteScheduledMessage
  • chat_getPermalink
  • @@ -14371,6 +14741,8 @@

    chat_postMessage
  • chat_scheduleMessage
  • chat_scheduledMessages_list
  • +
  • chat_startStream
  • +
  • chat_stopStream
  • chat_unfurl
  • chat_update
  • conversations_acceptSharedInvite
  • @@ -14513,6 +14885,10 @@

    views_publish
  • views_push
  • views_update
  • +
  • workflows_featured_add
  • +
  • workflows_featured_list
  • +
  • workflows_featured_remove
  • +
  • workflows_featured_set
  • workflows_stepCompleted
  • workflows_stepFailed
  • workflows_updateStep
  • diff --git a/docs/reference/web/client.html b/docs/reference/web/client.html index 28212dff5..9e743c5b8 100644 --- a/docs/reference/web/client.html +++ b/docs/reference/web/client.html @@ -1752,7 +1752,7 @@

    Classes

    def admin_users_list( self, *, - team_id: str, + team_id: Optional[str] = None, include_deactivated_user_workspaces: Optional[bool] = None, is_active: Optional[bool] = None, cursor: Optional[str] = None, @@ -2097,12 +2097,15 @@

    Classes

    channel_id: str, thread_ts: str, status: str, + loading_messages: Optional[List[str]] = None, **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus """ - kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "status": status}) + kwargs.update( + {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} + ) return self.api_call("assistant.threads.setStatus", params=kwargs) def assistant_threads_setTitle( @@ -2113,7 +2116,7 @@

    Classes

    title: str, **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set the title for the given assistant thread. https://api.slack.com/methods/assistant.threads.setTitle """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "title": title}) @@ -2128,7 +2131,7 @@

    Classes

    prompts: List[Dict[str, str]], **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set suggested prompts for the given assistant thread. https://api.slack.com/methods/assistant.threads.setSuggestedPrompts """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "prompts": prompts}) @@ -2642,6 +2645,26 @@

    Classes

    # -------------------------- + def chat_appendStream( + self, + *, + channel: str, + ts: str, + markdown_text: str, + **kwargs, + ) -> SlackResponse: + """Appends text to an existing streaming conversation. + https://api.slack.com/methods/chat.appendStream + """ + kwargs.update( + { + "channel": channel, + "ts": ts, + "markdown_text": markdown_text, + } + ) + return self.api_call("chat.appendStream", params=kwargs) + def chat_delete( self, *, @@ -2717,6 +2740,7 @@

    Classes

    link_names: Optional[bool] = None, username: Optional[str] = None, parse: Optional[str] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Sends an ephemeral message to a user in a channel. @@ -2736,11 +2760,12 @@

    Classes

    "link_names": link_names, "username": username, "parse": parse, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postEphemeral", kwargs) + _warn_if_message_text_content_is_missing("chat.postEphemeral", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.postEphemeral", json=kwargs) @@ -2764,6 +2789,7 @@

    Classes

    username: Optional[str] = None, parse: Optional[str] = None, # none, full metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Sends a message to a channel. @@ -2788,11 +2814,12 @@

    Classes

    "username": username, "parse": parse, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.postMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.postMessage", json=kwargs) @@ -2801,7 +2828,7 @@

    Classes

    *, channel: str, post_at: Union[str, int], - text: str, + text: Optional[str] = None, as_user: Optional[bool] = None, attachments: Optional[Union[str, Sequence[Union[Dict, Attachment]]]] = None, blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, @@ -2812,6 +2839,7 @@

    Classes

    unfurl_media: Optional[bool] = None, link_names: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Schedules a message. @@ -2832,14 +2860,90 @@

    Classes

    "unfurl_media": unfurl_media, "link_names": link_names, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.scheduleMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.scheduleMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.scheduleMessage", json=kwargs) + def chat_scheduledMessages_list( + self, + *, + channel: Optional[str] = None, + cursor: Optional[str] = None, + latest: Optional[str] = None, + limit: Optional[int] = None, + oldest: Optional[str] = None, + team_id: Optional[str] = None, + **kwargs, + ) -> SlackResponse: + """Lists all scheduled messages. + https://api.slack.com/methods/chat.scheduledMessages.list + """ + kwargs.update( + { + "channel": channel, + "cursor": cursor, + "latest": latest, + "limit": limit, + "oldest": oldest, + "team_id": team_id, + } + ) + return self.api_call("chat.scheduledMessages.list", params=kwargs) + + def chat_startStream( + self, + *, + channel: str, + thread_ts: Optional[str] = None, + markdown_text: Optional[str] = None, + unfurl_links: Optional[bool] = None, + unfurl_media: Optional[bool] = None, + **kwargs, + ) -> SlackResponse: + """Starts a new streaming conversation. + https://api.slack.com/methods/chat.startStream + """ + kwargs.update( + { + "channel": channel, + "thread_ts": thread_ts, + "markdown_text": markdown_text, + "unfurl_links": unfurl_links, + "unfurl_media": unfurl_media, + } + ) + return self.api_call("chat.startStream", params=kwargs) + + def chat_stopStream( + self, + *, + channel: str, + ts: str, + markdown_text: Optional[str] = None, + blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, + metadata: Optional[Union[Dict, Metadata]] = None, + **kwargs, + ) -> SlackResponse: + """Stops a streaming conversation. + https://api.slack.com/methods/chat.stopStream + """ + kwargs.update( + { + "channel": channel, + "ts": ts, + "markdown_text": markdown_text, + "blocks": blocks, + "metadata": metadata, + } + ) + _parse_web_class_objects(kwargs) + return self.api_call("chat.stopStream", params=kwargs) + def chat_unfurl( self, *, @@ -2889,6 +2993,7 @@

    Classes

    parse: Optional[str] = None, # none, full reply_broadcast: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Updates a message in a channel. @@ -2906,6 +3011,7 @@

    Classes

    "parse": parse, "reply_broadcast": reply_broadcast, "metadata": metadata, + "markdown_text": markdown_text, } ) if isinstance(file_ids, (list, tuple)): @@ -2914,36 +3020,10 @@

    Classes

    kwargs.update({"file_ids": file_ids}) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.update", kwargs) + _warn_if_message_text_content_is_missing("chat.update", kwargs) # NOTE: intentionally using json over params for API methods using blocks/attachments return self.api_call("chat.update", json=kwargs) - def chat_scheduledMessages_list( - self, - *, - channel: Optional[str] = None, - cursor: Optional[str] = None, - latest: Optional[str] = None, - limit: Optional[int] = None, - oldest: Optional[str] = None, - team_id: Optional[str] = None, - **kwargs, - ) -> SlackResponse: - """Lists all scheduled messages. - https://api.slack.com/methods/chat.scheduledMessages.list - """ - kwargs.update( - { - "channel": channel, - "cursor": cursor, - "latest": latest, - "limit": limit, - "oldest": oldest, - "team_id": team_id, - } - ) - return self.api_call("chat.scheduledMessages.list", params=kwargs) - def conversations_acceptSharedInvite( self, *, @@ -5438,6 +5518,72 @@

    Classes

    # NOTE: Intentionally using json for the "view" parameter return self.api_call("views.publish", json=kwargs) + def workflows_featured_add( + self, + *, + channel_id: str, + trigger_ids: Union[str, Sequence[str]], + **kwargs, + ) -> SlackResponse: + """Add featured workflows to a channel. + https://api.slack.com/methods/workflows.featured.add + """ + kwargs.update({"channel_id": channel_id}) + if isinstance(trigger_ids, (list, tuple)): + kwargs.update({"trigger_ids": ",".join(trigger_ids)}) + else: + kwargs.update({"trigger_ids": trigger_ids}) + return self.api_call("workflows.featured.add", params=kwargs) + + def workflows_featured_list( + self, + *, + channel_ids: Union[str, Sequence[str]], + **kwargs, + ) -> SlackResponse: + """List the featured workflows for specified channels. + https://api.slack.com/methods/workflows.featured.list + """ + if isinstance(channel_ids, (list, tuple)): + kwargs.update({"channel_ids": ",".join(channel_ids)}) + else: + kwargs.update({"channel_ids": channel_ids}) + return self.api_call("workflows.featured.list", params=kwargs) + + def workflows_featured_remove( + self, + *, + channel_id: str, + trigger_ids: Union[str, Sequence[str]], + **kwargs, + ) -> SlackResponse: + """Remove featured workflows from a channel. + https://api.slack.com/methods/workflows.featured.remove + """ + kwargs.update({"channel_id": channel_id}) + if isinstance(trigger_ids, (list, tuple)): + kwargs.update({"trigger_ids": ",".join(trigger_ids)}) + else: + kwargs.update({"trigger_ids": trigger_ids}) + return self.api_call("workflows.featured.remove", params=kwargs) + + def workflows_featured_set( + self, + *, + channel_id: str, + trigger_ids: Union[str, Sequence[str]], + **kwargs, + ) -> SlackResponse: + """Set featured workflows for a channel. + https://api.slack.com/methods/workflows.featured.set + """ + kwargs.update({"channel_id": channel_id}) + if isinstance(trigger_ids, (list, tuple)): + kwargs.update({"trigger_ids": ",".join(trigger_ids)}) + else: + kwargs.update({"trigger_ids": trigger_ids}) + return self.api_call("workflows.featured.set", params=kwargs) + def workflows_stepCompleted( self, *, @@ -7915,7 +8061,7 @@

    Methods

    https://api.slack.com/methods/admin.users.invite

    -def admin_users_list(self,
    *,
    team_id: str,
    include_deactivated_user_workspaces: bool | None = None,
    is_active: bool | None = None,
    cursor: str | None = None,
    limit: int | None = None,
    **kwargs) ‑> SlackResponse
    +def admin_users_list(self,
    *,
    team_id: str | None = None,
    include_deactivated_user_workspaces: bool | None = None,
    is_active: bool | None = None,
    cursor: str | None = None,
    limit: int | None = None,
    **kwargs) ‑> SlackResponse
    @@ -7925,7 +8071,7 @@

    Methods

    def admin_users_list(
         self,
         *,
    -    team_id: str,
    +    team_id: Optional[str] = None,
         include_deactivated_user_workspaces: Optional[bool] = None,
         is_active: Optional[bool] = None,
         cursor: Optional[str] = None,
    @@ -8712,7 +8858,7 @@ 

    Methods

    https://api.slack.com/methods/apps.uninstall

    -def assistant_threads_setStatus(self, *, channel_id: str, thread_ts: str, status: str, **kwargs) ‑> SlackResponse +def assistant_threads_setStatus(self,
    *,
    channel_id: str,
    thread_ts: str,
    status: str,
    loading_messages: List[str] | None = None,
    **kwargs) ‑> SlackResponse
    @@ -8725,15 +8871,18 @@

    Methods

    channel_id: str, thread_ts: str, status: str, + loading_messages: Optional[List[str]] = None, **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus """ - kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "status": status}) + kwargs.update( + {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} + ) return self.api_call("assistant.threads.setStatus", params=kwargs)
    -

    Revokes a token. +

    Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus

    @@ -8753,7 +8902,7 @@

    Methods

    prompts: List[Dict[str, str]], **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set suggested prompts for the given assistant thread. https://api.slack.com/methods/assistant.threads.setSuggestedPrompts """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "prompts": prompts}) @@ -8761,7 +8910,7 @@

    Methods

    kwargs.update({"title": title}) return self.api_call("assistant.threads.setSuggestedPrompts", json=kwargs)
    -

    Revokes a token. +

    Set suggested prompts for the given assistant thread. https://api.slack.com/methods/assistant.threads.setSuggestedPrompts

    @@ -8780,13 +8929,13 @@

    Methods

    title: str, **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set the title for the given assistant thread. https://api.slack.com/methods/assistant.threads.setTitle """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "title": title}) return self.api_call("assistant.threads.setTitle", params=kwargs)
    -

    Revokes a token. +

    Set the title for the given assistant thread. https://api.slack.com/methods/assistant.threads.setTitle

    @@ -9657,6 +9806,37 @@

    Methods

    Unarchives a channel.

    +
    +def chat_appendStream(self, *, channel: str, ts: str, markdown_text: str, **kwargs) ‑> SlackResponse +
    +
    +
    + +Expand source code + +
    def chat_appendStream(
    +    self,
    +    *,
    +    channel: str,
    +    ts: str,
    +    markdown_text: str,
    +    **kwargs,
    +) -> SlackResponse:
    +    """Appends text to an existing streaming conversation.
    +    https://api.slack.com/methods/chat.appendStream
    +    """
    +    kwargs.update(
    +        {
    +            "channel": channel,
    +            "ts": ts,
    +            "markdown_text": markdown_text,
    +        }
    +    )
    +    return self.api_call("chat.appendStream", params=kwargs)
    +
    +

    Appends text to an existing streaming conversation. +https://api.slack.com/methods/chat.appendStream

    +
    def chat_delete(self, *, channel: str, ts: str, as_user: bool | None = None, **kwargs) ‑> SlackResponse
    @@ -9762,7 +9942,7 @@

    Methods

    https://api.slack.com/methods/chat.meMessage

    -def chat_postEphemeral(self,
    *,
    channel: str,
    user: str,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    icon_emoji: str | None = None,
    icon_url: str | None = None,
    link_names: bool | None = None,
    username: str | None = None,
    parse: str | None = None,
    **kwargs) ‑> SlackResponse
    +def chat_postEphemeral(self,
    *,
    channel: str,
    user: str,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    icon_emoji: str | None = None,
    icon_url: str | None = None,
    link_names: bool | None = None,
    username: str | None = None,
    parse: str | None = None,
    markdown_text: str | None = None,
    **kwargs) ‑> SlackResponse
    @@ -9784,6 +9964,7 @@

    Methods

    link_names: Optional[bool] = None, username: Optional[str] = None, parse: Optional[str] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Sends an ephemeral message to a user in a channel. @@ -9803,11 +9984,12 @@

    Methods

    "link_names": link_names, "username": username, "parse": parse, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postEphemeral", kwargs) + _warn_if_message_text_content_is_missing("chat.postEphemeral", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.postEphemeral", json=kwargs)
    @@ -9815,7 +9997,7 @@

    Methods

    https://api.slack.com/methods/chat.postEphemeral

    -def chat_postMessage(self,
    *,
    channel: str,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    reply_broadcast: bool | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    container_id: str | None = None,
    icon_emoji: str | None = None,
    icon_url: str | None = None,
    mrkdwn: bool | None = None,
    link_names: bool | None = None,
    username: str | None = None,
    parse: str | None = None,
    metadata: Dict | Metadata | None = None,
    **kwargs) ‑> SlackResponse
    +def chat_postMessage(self,
    *,
    channel: str,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    reply_broadcast: bool | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    container_id: str | None = None,
    icon_emoji: str | None = None,
    icon_url: str | None = None,
    mrkdwn: bool | None = None,
    link_names: bool | None = None,
    username: str | None = None,
    parse: str | None = None,
    metadata: Dict | Metadata | None = None,
    markdown_text: str | None = None,
    **kwargs) ‑> SlackResponse
    @@ -9842,6 +10024,7 @@

    Methods

    username: Optional[str] = None, parse: Optional[str] = None, # none, full metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Sends a message to a channel. @@ -9866,11 +10049,12 @@

    Methods

    "username": username, "parse": parse, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.postMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.postMessage", json=kwargs)
    @@ -9878,7 +10062,7 @@

    Methods

    https://api.slack.com/methods/chat.postMessage

    -def chat_scheduleMessage(self,
    *,
    channel: str,
    post_at: str | int,
    text: str,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    parse: str | None = None,
    reply_broadcast: bool | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    link_names: bool | None = None,
    metadata: Dict | Metadata | None = None,
    **kwargs) ‑> SlackResponse
    +def chat_scheduleMessage(self,
    *,
    channel: str,
    post_at: str | int,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    parse: str | None = None,
    reply_broadcast: bool | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    link_names: bool | None = None,
    metadata: Dict | Metadata | None = None,
    markdown_text: str | None = None,
    **kwargs) ‑> SlackResponse
    @@ -9890,7 +10074,7 @@

    Methods

    *, channel: str, post_at: Union[str, int], - text: str, + text: Optional[str] = None, as_user: Optional[bool] = None, attachments: Optional[Union[str, Sequence[Union[Dict, Attachment]]]] = None, blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, @@ -9901,6 +10085,7 @@

    Methods

    unfurl_media: Optional[bool] = None, link_names: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Schedules a message. @@ -9921,11 +10106,12 @@

    Methods

    "unfurl_media": unfurl_media, "link_names": link_names, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.scheduleMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.scheduleMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.scheduleMessage", json=kwargs)
    @@ -9969,6 +10155,77 @@

    Methods

    +
    +def chat_startStream(self,
    *,
    channel: str,
    thread_ts: str | None = None,
    markdown_text: str | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    **kwargs) ‑> SlackResponse
    +
    +
    +
    + +Expand source code + +
    def chat_startStream(
    +    self,
    +    *,
    +    channel: str,
    +    thread_ts: Optional[str] = None,
    +    markdown_text: Optional[str] = None,
    +    unfurl_links: Optional[bool] = None,
    +    unfurl_media: Optional[bool] = None,
    +    **kwargs,
    +) -> SlackResponse:
    +    """Starts a new streaming conversation.
    +    https://api.slack.com/methods/chat.startStream
    +    """
    +    kwargs.update(
    +        {
    +            "channel": channel,
    +            "thread_ts": thread_ts,
    +            "markdown_text": markdown_text,
    +            "unfurl_links": unfurl_links,
    +            "unfurl_media": unfurl_media,
    +        }
    +    )
    +    return self.api_call("chat.startStream", params=kwargs)
    +
    +

    Starts a new streaming conversation. +https://api.slack.com/methods/chat.startStream

    +
    +
    +def chat_stopStream(self,
    *,
    channel: str,
    ts: str,
    markdown_text: str | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    metadata: Dict | Metadata | None = None,
    **kwargs) ‑> SlackResponse
    +
    +
    +
    + +Expand source code + +
    def chat_stopStream(
    +    self,
    +    *,
    +    channel: str,
    +    ts: str,
    +    markdown_text: Optional[str] = None,
    +    blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None,
    +    metadata: Optional[Union[Dict, Metadata]] = None,
    +    **kwargs,
    +) -> SlackResponse:
    +    """Stops a streaming conversation.
    +    https://api.slack.com/methods/chat.stopStream
    +    """
    +    kwargs.update(
    +        {
    +            "channel": channel,
    +            "ts": ts,
    +            "markdown_text": markdown_text,
    +            "blocks": blocks,
    +            "metadata": metadata,
    +        }
    +    )
    +    _parse_web_class_objects(kwargs)
    +    return self.api_call("chat.stopStream", params=kwargs)
    +
    +

    Stops a streaming conversation. +https://api.slack.com/methods/chat.stopStream

    +
    def chat_unfurl(self,
    *,
    channel: str | None = None,
    ts: str | None = None,
    source: str | None = None,
    unfurl_id: str | None = None,
    unfurls: Dict[str, Dict] | None = None,
    user_auth_blocks: str | Sequence[Dict | Block] | None = None,
    user_auth_message: str | None = None,
    user_auth_required: bool | None = None,
    user_auth_url: str | None = None,
    **kwargs) ‑> SlackResponse
    @@ -10016,7 +10273,7 @@

    Methods

    https://api.slack.com/methods/chat.unfurl

    -def chat_update(self,
    *,
    channel: str,
    ts: str,
    text: str | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    as_user: bool | None = None,
    file_ids: str | Sequence[str] | None = None,
    link_names: bool | None = None,
    parse: str | None = None,
    reply_broadcast: bool | None = None,
    metadata: Dict | Metadata | None = None,
    **kwargs) ‑> SlackResponse
    +def chat_update(self,
    *,
    channel: str,
    ts: str,
    text: str | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    as_user: bool | None = None,
    file_ids: str | Sequence[str] | None = None,
    link_names: bool | None = None,
    parse: str | None = None,
    reply_broadcast: bool | None = None,
    metadata: Dict | Metadata | None = None,
    markdown_text: str | None = None,
    **kwargs) ‑> SlackResponse
    @@ -10037,6 +10294,7 @@

    Methods

    parse: Optional[str] = None, # none, full reply_broadcast: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Updates a message in a channel. @@ -10054,6 +10312,7 @@

    Methods

    "parse": parse, "reply_broadcast": reply_broadcast, "metadata": metadata, + "markdown_text": markdown_text, } ) if isinstance(file_ids, (list, tuple)): @@ -10062,7 +10321,7 @@

    Methods

    kwargs.update({"file_ids": file_ids}) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.update", kwargs) + _warn_if_message_text_content_is_missing("chat.update", kwargs) # NOTE: intentionally using json over params for API methods using blocks/attachments return self.api_call("chat.update", json=kwargs)
    @@ -14090,6 +14349,116 @@

    Methods

    to learn more about updating views and avoiding race conditions with the hash argument. https://api.slack.com/methods/views.update

    + +
    +
    + +Expand source code + +
    def workflows_featured_add(
    +    self,
    +    *,
    +    channel_id: str,
    +    trigger_ids: Union[str, Sequence[str]],
    +    **kwargs,
    +) -> SlackResponse:
    +    """Add featured workflows to a channel.
    +    https://api.slack.com/methods/workflows.featured.add
    +    """
    +    kwargs.update({"channel_id": channel_id})
    +    if isinstance(trigger_ids, (list, tuple)):
    +        kwargs.update({"trigger_ids": ",".join(trigger_ids)})
    +    else:
    +        kwargs.update({"trigger_ids": trigger_ids})
    +    return self.api_call("workflows.featured.add", params=kwargs)
    +
    +

    Add featured workflows to a channel. +https://api.slack.com/methods/workflows.featured.add

    +
    + +
    +
    + +Expand source code + +
    def workflows_featured_list(
    +    self,
    +    *,
    +    channel_ids: Union[str, Sequence[str]],
    +    **kwargs,
    +) -> SlackResponse:
    +    """List the featured workflows for specified channels.
    +    https://api.slack.com/methods/workflows.featured.list
    +    """
    +    if isinstance(channel_ids, (list, tuple)):
    +        kwargs.update({"channel_ids": ",".join(channel_ids)})
    +    else:
    +        kwargs.update({"channel_ids": channel_ids})
    +    return self.api_call("workflows.featured.list", params=kwargs)
    +
    +

    List the featured workflows for specified channels. +https://api.slack.com/methods/workflows.featured.list

    +
    + +
    +
    + +Expand source code + +
    def workflows_featured_remove(
    +    self,
    +    *,
    +    channel_id: str,
    +    trigger_ids: Union[str, Sequence[str]],
    +    **kwargs,
    +) -> SlackResponse:
    +    """Remove featured workflows from a channel.
    +    https://api.slack.com/methods/workflows.featured.remove
    +    """
    +    kwargs.update({"channel_id": channel_id})
    +    if isinstance(trigger_ids, (list, tuple)):
    +        kwargs.update({"trigger_ids": ",".join(trigger_ids)})
    +    else:
    +        kwargs.update({"trigger_ids": trigger_ids})
    +    return self.api_call("workflows.featured.remove", params=kwargs)
    +
    +

    Remove featured workflows from a channel. +https://api.slack.com/methods/workflows.featured.remove

    +
    + +
    +
    + +Expand source code + +
    def workflows_featured_set(
    +    self,
    +    *,
    +    channel_id: str,
    +    trigger_ids: Union[str, Sequence[str]],
    +    **kwargs,
    +) -> SlackResponse:
    +    """Set featured workflows for a channel.
    +    https://api.slack.com/methods/workflows.featured.set
    +    """
    +    kwargs.update({"channel_id": channel_id})
    +    if isinstance(trigger_ids, (list, tuple)):
    +        kwargs.update({"trigger_ids": ",".join(trigger_ids)})
    +    else:
    +        kwargs.update({"trigger_ids": trigger_ids})
    +    return self.api_call("workflows.featured.set", params=kwargs)
    +
    +

    Set featured workflows for a channel. +https://api.slack.com/methods/workflows.featured.set

    +
    def workflows_stepCompleted(self, *, workflow_step_execute_id: str, outputs: dict | None = None, **kwargs) ‑> SlackResponse
    @@ -14362,6 +14731,7 @@

    channels_setPurpose
  • channels_setTopic
  • channels_unarchive
  • +
  • chat_appendStream
  • chat_delete
  • chat_deleteScheduledMessage
  • chat_getPermalink
  • @@ -14370,6 +14740,8 @@

    chat_postMessage
  • chat_scheduleMessage
  • chat_scheduledMessages_list
  • +
  • chat_startStream
  • +
  • chat_stopStream
  • chat_unfurl
  • chat_update
  • conversations_acceptSharedInvite
  • @@ -14512,6 +14884,10 @@

    views_publish
  • views_push
  • views_update
  • +
  • workflows_featured_add
  • +
  • workflows_featured_list
  • +
  • workflows_featured_remove
  • +
  • workflows_featured_set
  • workflows_stepCompleted
  • workflows_stepFailed
  • workflows_updateStep
  • diff --git a/docs/reference/web/index.html b/docs/reference/web/index.html index e4ac7ea49..27a78aa62 100644 --- a/docs/reference/web/index.html +++ b/docs/reference/web/index.html @@ -2113,7 +2113,7 @@

    Raises

    def admin_users_list( self, *, - team_id: str, + team_id: Optional[str] = None, include_deactivated_user_workspaces: Optional[bool] = None, is_active: Optional[bool] = None, cursor: Optional[str] = None, @@ -2458,12 +2458,15 @@

    Raises

    channel_id: str, thread_ts: str, status: str, + loading_messages: Optional[List[str]] = None, **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus """ - kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "status": status}) + kwargs.update( + {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} + ) return self.api_call("assistant.threads.setStatus", params=kwargs) def assistant_threads_setTitle( @@ -2474,7 +2477,7 @@

    Raises

    title: str, **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set the title for the given assistant thread. https://api.slack.com/methods/assistant.threads.setTitle """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "title": title}) @@ -2489,7 +2492,7 @@

    Raises

    prompts: List[Dict[str, str]], **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set suggested prompts for the given assistant thread. https://api.slack.com/methods/assistant.threads.setSuggestedPrompts """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "prompts": prompts}) @@ -3003,6 +3006,26 @@

    Raises

    # -------------------------- + def chat_appendStream( + self, + *, + channel: str, + ts: str, + markdown_text: str, + **kwargs, + ) -> SlackResponse: + """Appends text to an existing streaming conversation. + https://api.slack.com/methods/chat.appendStream + """ + kwargs.update( + { + "channel": channel, + "ts": ts, + "markdown_text": markdown_text, + } + ) + return self.api_call("chat.appendStream", params=kwargs) + def chat_delete( self, *, @@ -3078,6 +3101,7 @@

    Raises

    link_names: Optional[bool] = None, username: Optional[str] = None, parse: Optional[str] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Sends an ephemeral message to a user in a channel. @@ -3097,11 +3121,12 @@

    Raises

    "link_names": link_names, "username": username, "parse": parse, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postEphemeral", kwargs) + _warn_if_message_text_content_is_missing("chat.postEphemeral", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.postEphemeral", json=kwargs) @@ -3125,6 +3150,7 @@

    Raises

    username: Optional[str] = None, parse: Optional[str] = None, # none, full metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Sends a message to a channel. @@ -3149,11 +3175,12 @@

    Raises

    "username": username, "parse": parse, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.postMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.postMessage", json=kwargs) @@ -3162,7 +3189,7 @@

    Raises

    *, channel: str, post_at: Union[str, int], - text: str, + text: Optional[str] = None, as_user: Optional[bool] = None, attachments: Optional[Union[str, Sequence[Union[Dict, Attachment]]]] = None, blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, @@ -3173,6 +3200,7 @@

    Raises

    unfurl_media: Optional[bool] = None, link_names: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Schedules a message. @@ -3193,14 +3221,90 @@

    Raises

    "unfurl_media": unfurl_media, "link_names": link_names, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.scheduleMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.scheduleMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.scheduleMessage", json=kwargs) + def chat_scheduledMessages_list( + self, + *, + channel: Optional[str] = None, + cursor: Optional[str] = None, + latest: Optional[str] = None, + limit: Optional[int] = None, + oldest: Optional[str] = None, + team_id: Optional[str] = None, + **kwargs, + ) -> SlackResponse: + """Lists all scheduled messages. + https://api.slack.com/methods/chat.scheduledMessages.list + """ + kwargs.update( + { + "channel": channel, + "cursor": cursor, + "latest": latest, + "limit": limit, + "oldest": oldest, + "team_id": team_id, + } + ) + return self.api_call("chat.scheduledMessages.list", params=kwargs) + + def chat_startStream( + self, + *, + channel: str, + thread_ts: Optional[str] = None, + markdown_text: Optional[str] = None, + unfurl_links: Optional[bool] = None, + unfurl_media: Optional[bool] = None, + **kwargs, + ) -> SlackResponse: + """Starts a new streaming conversation. + https://api.slack.com/methods/chat.startStream + """ + kwargs.update( + { + "channel": channel, + "thread_ts": thread_ts, + "markdown_text": markdown_text, + "unfurl_links": unfurl_links, + "unfurl_media": unfurl_media, + } + ) + return self.api_call("chat.startStream", params=kwargs) + + def chat_stopStream( + self, + *, + channel: str, + ts: str, + markdown_text: Optional[str] = None, + blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, + metadata: Optional[Union[Dict, Metadata]] = None, + **kwargs, + ) -> SlackResponse: + """Stops a streaming conversation. + https://api.slack.com/methods/chat.stopStream + """ + kwargs.update( + { + "channel": channel, + "ts": ts, + "markdown_text": markdown_text, + "blocks": blocks, + "metadata": metadata, + } + ) + _parse_web_class_objects(kwargs) + return self.api_call("chat.stopStream", params=kwargs) + def chat_unfurl( self, *, @@ -3250,6 +3354,7 @@

    Raises

    parse: Optional[str] = None, # none, full reply_broadcast: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Updates a message in a channel. @@ -3267,6 +3372,7 @@

    Raises

    "parse": parse, "reply_broadcast": reply_broadcast, "metadata": metadata, + "markdown_text": markdown_text, } ) if isinstance(file_ids, (list, tuple)): @@ -3275,36 +3381,10 @@

    Raises

    kwargs.update({"file_ids": file_ids}) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.update", kwargs) + _warn_if_message_text_content_is_missing("chat.update", kwargs) # NOTE: intentionally using json over params for API methods using blocks/attachments return self.api_call("chat.update", json=kwargs) - def chat_scheduledMessages_list( - self, - *, - channel: Optional[str] = None, - cursor: Optional[str] = None, - latest: Optional[str] = None, - limit: Optional[int] = None, - oldest: Optional[str] = None, - team_id: Optional[str] = None, - **kwargs, - ) -> SlackResponse: - """Lists all scheduled messages. - https://api.slack.com/methods/chat.scheduledMessages.list - """ - kwargs.update( - { - "channel": channel, - "cursor": cursor, - "latest": latest, - "limit": limit, - "oldest": oldest, - "team_id": team_id, - } - ) - return self.api_call("chat.scheduledMessages.list", params=kwargs) - def conversations_acceptSharedInvite( self, *, @@ -5799,6 +5879,72 @@

    Raises

    # NOTE: Intentionally using json for the "view" parameter return self.api_call("views.publish", json=kwargs) + def workflows_featured_add( + self, + *, + channel_id: str, + trigger_ids: Union[str, Sequence[str]], + **kwargs, + ) -> SlackResponse: + """Add featured workflows to a channel. + https://api.slack.com/methods/workflows.featured.add + """ + kwargs.update({"channel_id": channel_id}) + if isinstance(trigger_ids, (list, tuple)): + kwargs.update({"trigger_ids": ",".join(trigger_ids)}) + else: + kwargs.update({"trigger_ids": trigger_ids}) + return self.api_call("workflows.featured.add", params=kwargs) + + def workflows_featured_list( + self, + *, + channel_ids: Union[str, Sequence[str]], + **kwargs, + ) -> SlackResponse: + """List the featured workflows for specified channels. + https://api.slack.com/methods/workflows.featured.list + """ + if isinstance(channel_ids, (list, tuple)): + kwargs.update({"channel_ids": ",".join(channel_ids)}) + else: + kwargs.update({"channel_ids": channel_ids}) + return self.api_call("workflows.featured.list", params=kwargs) + + def workflows_featured_remove( + self, + *, + channel_id: str, + trigger_ids: Union[str, Sequence[str]], + **kwargs, + ) -> SlackResponse: + """Remove featured workflows from a channel. + https://api.slack.com/methods/workflows.featured.remove + """ + kwargs.update({"channel_id": channel_id}) + if isinstance(trigger_ids, (list, tuple)): + kwargs.update({"trigger_ids": ",".join(trigger_ids)}) + else: + kwargs.update({"trigger_ids": trigger_ids}) + return self.api_call("workflows.featured.remove", params=kwargs) + + def workflows_featured_set( + self, + *, + channel_id: str, + trigger_ids: Union[str, Sequence[str]], + **kwargs, + ) -> SlackResponse: + """Set featured workflows for a channel. + https://api.slack.com/methods/workflows.featured.set + """ + kwargs.update({"channel_id": channel_id}) + if isinstance(trigger_ids, (list, tuple)): + kwargs.update({"trigger_ids": ",".join(trigger_ids)}) + else: + kwargs.update({"trigger_ids": trigger_ids}) + return self.api_call("workflows.featured.set", params=kwargs) + def workflows_stepCompleted( self, *, @@ -8276,7 +8422,7 @@

    Methods

    https://api.slack.com/methods/admin.users.invite

    -def admin_users_list(self,
    *,
    team_id: str,
    include_deactivated_user_workspaces: bool | None = None,
    is_active: bool | None = None,
    cursor: str | None = None,
    limit: int | None = None,
    **kwargs) ‑> SlackResponse
    +def admin_users_list(self,
    *,
    team_id: str | None = None,
    include_deactivated_user_workspaces: bool | None = None,
    is_active: bool | None = None,
    cursor: str | None = None,
    limit: int | None = None,
    **kwargs) ‑> SlackResponse
    @@ -8286,7 +8432,7 @@

    Methods

    def admin_users_list(
         self,
         *,
    -    team_id: str,
    +    team_id: Optional[str] = None,
         include_deactivated_user_workspaces: Optional[bool] = None,
         is_active: Optional[bool] = None,
         cursor: Optional[str] = None,
    @@ -9073,7 +9219,7 @@ 

    Methods

    https://api.slack.com/methods/apps.uninstall

    -def assistant_threads_setStatus(self, *, channel_id: str, thread_ts: str, status: str, **kwargs) ‑> SlackResponse +def assistant_threads_setStatus(self,
    *,
    channel_id: str,
    thread_ts: str,
    status: str,
    loading_messages: List[str] | None = None,
    **kwargs) ‑> SlackResponse
    @@ -9086,15 +9232,18 @@

    Methods

    channel_id: str, thread_ts: str, status: str, + loading_messages: Optional[List[str]] = None, **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus """ - kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "status": status}) + kwargs.update( + {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} + ) return self.api_call("assistant.threads.setStatus", params=kwargs)
    -

    Revokes a token. +

    Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus

    @@ -9114,7 +9263,7 @@

    Methods

    prompts: List[Dict[str, str]], **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set suggested prompts for the given assistant thread. https://api.slack.com/methods/assistant.threads.setSuggestedPrompts """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "prompts": prompts}) @@ -9122,7 +9271,7 @@

    Methods

    kwargs.update({"title": title}) return self.api_call("assistant.threads.setSuggestedPrompts", json=kwargs)
    -

    Revokes a token. +

    Set suggested prompts for the given assistant thread. https://api.slack.com/methods/assistant.threads.setSuggestedPrompts

    @@ -9141,13 +9290,13 @@

    Methods

    title: str, **kwargs, ) -> SlackResponse: - """Revokes a token. + """Set the title for the given assistant thread. https://api.slack.com/methods/assistant.threads.setTitle """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "title": title}) return self.api_call("assistant.threads.setTitle", params=kwargs)
    -

    Revokes a token. +

    Set the title for the given assistant thread. https://api.slack.com/methods/assistant.threads.setTitle

    @@ -10018,6 +10167,37 @@

    Methods

    Unarchives a channel.

    +
    +def chat_appendStream(self, *, channel: str, ts: str, markdown_text: str, **kwargs) ‑> SlackResponse +
    +
    +
    + +Expand source code + +
    def chat_appendStream(
    +    self,
    +    *,
    +    channel: str,
    +    ts: str,
    +    markdown_text: str,
    +    **kwargs,
    +) -> SlackResponse:
    +    """Appends text to an existing streaming conversation.
    +    https://api.slack.com/methods/chat.appendStream
    +    """
    +    kwargs.update(
    +        {
    +            "channel": channel,
    +            "ts": ts,
    +            "markdown_text": markdown_text,
    +        }
    +    )
    +    return self.api_call("chat.appendStream", params=kwargs)
    +
    +

    Appends text to an existing streaming conversation. +https://api.slack.com/methods/chat.appendStream

    +
    def chat_delete(self, *, channel: str, ts: str, as_user: bool | None = None, **kwargs) ‑> SlackResponse
    @@ -10123,7 +10303,7 @@

    Methods

    https://api.slack.com/methods/chat.meMessage

    -def chat_postEphemeral(self,
    *,
    channel: str,
    user: str,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    icon_emoji: str | None = None,
    icon_url: str | None = None,
    link_names: bool | None = None,
    username: str | None = None,
    parse: str | None = None,
    **kwargs) ‑> SlackResponse
    +def chat_postEphemeral(self,
    *,
    channel: str,
    user: str,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    icon_emoji: str | None = None,
    icon_url: str | None = None,
    link_names: bool | None = None,
    username: str | None = None,
    parse: str | None = None,
    markdown_text: str | None = None,
    **kwargs) ‑> SlackResponse
    @@ -10145,6 +10325,7 @@

    Methods

    link_names: Optional[bool] = None, username: Optional[str] = None, parse: Optional[str] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Sends an ephemeral message to a user in a channel. @@ -10164,11 +10345,12 @@

    Methods

    "link_names": link_names, "username": username, "parse": parse, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postEphemeral", kwargs) + _warn_if_message_text_content_is_missing("chat.postEphemeral", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.postEphemeral", json=kwargs)
    @@ -10176,7 +10358,7 @@

    Methods

    https://api.slack.com/methods/chat.postEphemeral

    -def chat_postMessage(self,
    *,
    channel: str,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    reply_broadcast: bool | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    container_id: str | None = None,
    icon_emoji: str | None = None,
    icon_url: str | None = None,
    mrkdwn: bool | None = None,
    link_names: bool | None = None,
    username: str | None = None,
    parse: str | None = None,
    metadata: Dict | Metadata | None = None,
    **kwargs) ‑> SlackResponse
    +def chat_postMessage(self,
    *,
    channel: str,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    reply_broadcast: bool | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    container_id: str | None = None,
    icon_emoji: str | None = None,
    icon_url: str | None = None,
    mrkdwn: bool | None = None,
    link_names: bool | None = None,
    username: str | None = None,
    parse: str | None = None,
    metadata: Dict | Metadata | None = None,
    markdown_text: str | None = None,
    **kwargs) ‑> SlackResponse
    @@ -10203,6 +10385,7 @@

    Methods

    username: Optional[str] = None, parse: Optional[str] = None, # none, full metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Sends a message to a channel. @@ -10227,11 +10410,12 @@

    Methods

    "username": username, "parse": parse, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.postMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.postMessage", json=kwargs)
    @@ -10239,7 +10423,7 @@

    Methods

    https://api.slack.com/methods/chat.postMessage

    -def chat_scheduleMessage(self,
    *,
    channel: str,
    post_at: str | int,
    text: str,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    parse: str | None = None,
    reply_broadcast: bool | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    link_names: bool | None = None,
    metadata: Dict | Metadata | None = None,
    **kwargs) ‑> SlackResponse
    +def chat_scheduleMessage(self,
    *,
    channel: str,
    post_at: str | int,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    parse: str | None = None,
    reply_broadcast: bool | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    link_names: bool | None = None,
    metadata: Dict | Metadata | None = None,
    markdown_text: str | None = None,
    **kwargs) ‑> SlackResponse
    @@ -10251,7 +10435,7 @@

    Methods

    *, channel: str, post_at: Union[str, int], - text: str, + text: Optional[str] = None, as_user: Optional[bool] = None, attachments: Optional[Union[str, Sequence[Union[Dict, Attachment]]]] = None, blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, @@ -10262,6 +10446,7 @@

    Methods

    unfurl_media: Optional[bool] = None, link_names: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Schedules a message. @@ -10282,11 +10467,12 @@

    Methods

    "unfurl_media": unfurl_media, "link_names": link_names, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.scheduleMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.scheduleMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.scheduleMessage", json=kwargs)
    @@ -10330,6 +10516,77 @@

    Methods

    +
    +def chat_startStream(self,
    *,
    channel: str,
    thread_ts: str | None = None,
    markdown_text: str | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    **kwargs) ‑> SlackResponse
    +
    +
    +
    + +Expand source code + +
    def chat_startStream(
    +    self,
    +    *,
    +    channel: str,
    +    thread_ts: Optional[str] = None,
    +    markdown_text: Optional[str] = None,
    +    unfurl_links: Optional[bool] = None,
    +    unfurl_media: Optional[bool] = None,
    +    **kwargs,
    +) -> SlackResponse:
    +    """Starts a new streaming conversation.
    +    https://api.slack.com/methods/chat.startStream
    +    """
    +    kwargs.update(
    +        {
    +            "channel": channel,
    +            "thread_ts": thread_ts,
    +            "markdown_text": markdown_text,
    +            "unfurl_links": unfurl_links,
    +            "unfurl_media": unfurl_media,
    +        }
    +    )
    +    return self.api_call("chat.startStream", params=kwargs)
    +
    +

    Starts a new streaming conversation. +https://api.slack.com/methods/chat.startStream

    +
    +
    +def chat_stopStream(self,
    *,
    channel: str,
    ts: str,
    markdown_text: str | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    metadata: Dict | Metadata | None = None,
    **kwargs) ‑> SlackResponse
    +
    +
    +
    + +Expand source code + +
    def chat_stopStream(
    +    self,
    +    *,
    +    channel: str,
    +    ts: str,
    +    markdown_text: Optional[str] = None,
    +    blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None,
    +    metadata: Optional[Union[Dict, Metadata]] = None,
    +    **kwargs,
    +) -> SlackResponse:
    +    """Stops a streaming conversation.
    +    https://api.slack.com/methods/chat.stopStream
    +    """
    +    kwargs.update(
    +        {
    +            "channel": channel,
    +            "ts": ts,
    +            "markdown_text": markdown_text,
    +            "blocks": blocks,
    +            "metadata": metadata,
    +        }
    +    )
    +    _parse_web_class_objects(kwargs)
    +    return self.api_call("chat.stopStream", params=kwargs)
    +
    +

    Stops a streaming conversation. +https://api.slack.com/methods/chat.stopStream

    +
    def chat_unfurl(self,
    *,
    channel: str | None = None,
    ts: str | None = None,
    source: str | None = None,
    unfurl_id: str | None = None,
    unfurls: Dict[str, Dict] | None = None,
    user_auth_blocks: str | Sequence[Dict | Block] | None = None,
    user_auth_message: str | None = None,
    user_auth_required: bool | None = None,
    user_auth_url: str | None = None,
    **kwargs) ‑> SlackResponse
    @@ -10377,7 +10634,7 @@

    Methods

    https://api.slack.com/methods/chat.unfurl

    -def chat_update(self,
    *,
    channel: str,
    ts: str,
    text: str | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    as_user: bool | None = None,
    file_ids: str | Sequence[str] | None = None,
    link_names: bool | None = None,
    parse: str | None = None,
    reply_broadcast: bool | None = None,
    metadata: Dict | Metadata | None = None,
    **kwargs) ‑> SlackResponse
    +def chat_update(self,
    *,
    channel: str,
    ts: str,
    text: str | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    as_user: bool | None = None,
    file_ids: str | Sequence[str] | None = None,
    link_names: bool | None = None,
    parse: str | None = None,
    reply_broadcast: bool | None = None,
    metadata: Dict | Metadata | None = None,
    markdown_text: str | None = None,
    **kwargs) ‑> SlackResponse
    @@ -10398,6 +10655,7 @@

    Methods

    parse: Optional[str] = None, # none, full reply_broadcast: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> SlackResponse: """Updates a message in a channel. @@ -10415,6 +10673,7 @@

    Methods

    "parse": parse, "reply_broadcast": reply_broadcast, "metadata": metadata, + "markdown_text": markdown_text, } ) if isinstance(file_ids, (list, tuple)): @@ -10423,7 +10682,7 @@

    Methods

    kwargs.update({"file_ids": file_ids}) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.update", kwargs) + _warn_if_message_text_content_is_missing("chat.update", kwargs) # NOTE: intentionally using json over params for API methods using blocks/attachments return self.api_call("chat.update", json=kwargs)
    @@ -14451,6 +14710,116 @@

    Methods

    to learn more about updating views and avoiding race conditions with the hash argument. https://api.slack.com/methods/views.update

    + +
    +
    + +Expand source code + +
    def workflows_featured_add(
    +    self,
    +    *,
    +    channel_id: str,
    +    trigger_ids: Union[str, Sequence[str]],
    +    **kwargs,
    +) -> SlackResponse:
    +    """Add featured workflows to a channel.
    +    https://api.slack.com/methods/workflows.featured.add
    +    """
    +    kwargs.update({"channel_id": channel_id})
    +    if isinstance(trigger_ids, (list, tuple)):
    +        kwargs.update({"trigger_ids": ",".join(trigger_ids)})
    +    else:
    +        kwargs.update({"trigger_ids": trigger_ids})
    +    return self.api_call("workflows.featured.add", params=kwargs)
    +
    +

    Add featured workflows to a channel. +https://api.slack.com/methods/workflows.featured.add

    +
    + +
    +
    + +Expand source code + +
    def workflows_featured_list(
    +    self,
    +    *,
    +    channel_ids: Union[str, Sequence[str]],
    +    **kwargs,
    +) -> SlackResponse:
    +    """List the featured workflows for specified channels.
    +    https://api.slack.com/methods/workflows.featured.list
    +    """
    +    if isinstance(channel_ids, (list, tuple)):
    +        kwargs.update({"channel_ids": ",".join(channel_ids)})
    +    else:
    +        kwargs.update({"channel_ids": channel_ids})
    +    return self.api_call("workflows.featured.list", params=kwargs)
    +
    +

    List the featured workflows for specified channels. +https://api.slack.com/methods/workflows.featured.list

    +
    + +
    +
    + +Expand source code + +
    def workflows_featured_remove(
    +    self,
    +    *,
    +    channel_id: str,
    +    trigger_ids: Union[str, Sequence[str]],
    +    **kwargs,
    +) -> SlackResponse:
    +    """Remove featured workflows from a channel.
    +    https://api.slack.com/methods/workflows.featured.remove
    +    """
    +    kwargs.update({"channel_id": channel_id})
    +    if isinstance(trigger_ids, (list, tuple)):
    +        kwargs.update({"trigger_ids": ",".join(trigger_ids)})
    +    else:
    +        kwargs.update({"trigger_ids": trigger_ids})
    +    return self.api_call("workflows.featured.remove", params=kwargs)
    +
    +

    Remove featured workflows from a channel. +https://api.slack.com/methods/workflows.featured.remove

    +
    + +
    +
    + +Expand source code + +
    def workflows_featured_set(
    +    self,
    +    *,
    +    channel_id: str,
    +    trigger_ids: Union[str, Sequence[str]],
    +    **kwargs,
    +) -> SlackResponse:
    +    """Set featured workflows for a channel.
    +    https://api.slack.com/methods/workflows.featured.set
    +    """
    +    kwargs.update({"channel_id": channel_id})
    +    if isinstance(trigger_ids, (list, tuple)):
    +        kwargs.update({"trigger_ids": ",".join(trigger_ids)})
    +    else:
    +        kwargs.update({"trigger_ids": trigger_ids})
    +    return self.api_call("workflows.featured.set", params=kwargs)
    +
    +

    Set featured workflows for a channel. +https://api.slack.com/methods/workflows.featured.set

    +
    def workflows_stepCompleted(self, *, workflow_step_execute_id: str, outputs: dict | None = None, **kwargs) ‑> SlackResponse
    @@ -14747,6 +15116,7 @@

    Web
  • channels_setPurpose
  • channels_setTopic
  • channels_unarchive
  • +
  • chat_appendStream
  • chat_delete
  • chat_deleteScheduledMessage
  • chat_getPermalink
  • @@ -14755,6 +15125,8 @@

    Web
  • chat_postMessage
  • chat_scheduleMessage
  • chat_scheduledMessages_list
  • +
  • chat_startStream
  • +
  • chat_stopStream
  • chat_unfurl
  • chat_update
  • conversations_acceptSharedInvite
  • @@ -14897,6 +15269,10 @@

    Web
  • views_publish
  • views_push
  • views_update
  • +
  • workflows_featured_add
  • +
  • workflows_featured_list
  • +
  • workflows_featured_remove
  • +
  • workflows_featured_set
  • workflows_stepCompleted
  • workflows_stepFailed
  • workflows_updateStep
  • diff --git a/docs/reference/web/internal_utils.html b/docs/reference/web/internal_utils.html index 9d8084d61..89227edce 100644 --- a/docs/reference/web/internal_utils.html +++ b/docs/reference/web/internal_utils.html @@ -95,7 +95,7 @@

    Returns

    Returns: The user agent string. - e.g. 'Python/3.6.7 slackclient/2.0.0 Darwin/17.7.0' + e.g. 'Python/3.7.17 slackclient/2.0.0 Darwin/17.7.0' """ # __name__ returns all classes, we only want the client client = "{0}/{1}".format("slackclient", version.__version__) @@ -110,7 +110,7 @@

    Returns

    Python version and OS version.

    Returns

    The user agent string. -e.g. 'Python/3.6.7 slackclient/2.0.0 Darwin/17.7.0'

    +e.g. 'Python/3.7.17 slackclient/2.0.0 Darwin/17.7.0'

    diff --git a/docs/reference/web/legacy_client.html b/docs/reference/web/legacy_client.html index 63cbfc7f9..37497b948 100644 --- a/docs/reference/web/legacy_client.html +++ b/docs/reference/web/legacy_client.html @@ -1751,7 +1751,7 @@

    Classes

    def admin_users_list( self, *, - team_id: str, + team_id: Optional[str] = None, include_deactivated_user_workspaces: Optional[bool] = None, is_active: Optional[bool] = None, cursor: Optional[str] = None, @@ -2096,12 +2096,15 @@

    Classes

    channel_id: str, thread_ts: str, status: str, + loading_messages: Optional[List[str]] = None, **kwargs, ) -> Union[Future, SlackResponse]: - """Revokes a token. + """Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus """ - kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "status": status}) + kwargs.update( + {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} + ) return self.api_call("assistant.threads.setStatus", params=kwargs) def assistant_threads_setTitle( @@ -2112,7 +2115,7 @@

    Classes

    title: str, **kwargs, ) -> Union[Future, SlackResponse]: - """Revokes a token. + """Set the title for the given assistant thread. https://api.slack.com/methods/assistant.threads.setTitle """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "title": title}) @@ -2127,7 +2130,7 @@

    Classes

    prompts: List[Dict[str, str]], **kwargs, ) -> Union[Future, SlackResponse]: - """Revokes a token. + """Set suggested prompts for the given assistant thread. https://api.slack.com/methods/assistant.threads.setSuggestedPrompts """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "prompts": prompts}) @@ -2641,6 +2644,26 @@

    Classes

    # -------------------------- + def chat_appendStream( + self, + *, + channel: str, + ts: str, + markdown_text: str, + **kwargs, + ) -> Union[Future, SlackResponse]: + """Appends text to an existing streaming conversation. + https://api.slack.com/methods/chat.appendStream + """ + kwargs.update( + { + "channel": channel, + "ts": ts, + "markdown_text": markdown_text, + } + ) + return self.api_call("chat.appendStream", params=kwargs) + def chat_delete( self, *, @@ -2716,6 +2739,7 @@

    Classes

    link_names: Optional[bool] = None, username: Optional[str] = None, parse: Optional[str] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> Union[Future, SlackResponse]: """Sends an ephemeral message to a user in a channel. @@ -2735,11 +2759,12 @@

    Classes

    "link_names": link_names, "username": username, "parse": parse, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postEphemeral", kwargs) + _warn_if_message_text_content_is_missing("chat.postEphemeral", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.postEphemeral", json=kwargs) @@ -2763,6 +2788,7 @@

    Classes

    username: Optional[str] = None, parse: Optional[str] = None, # none, full metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> Union[Future, SlackResponse]: """Sends a message to a channel. @@ -2787,11 +2813,12 @@

    Classes

    "username": username, "parse": parse, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.postMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.postMessage", json=kwargs) @@ -2800,7 +2827,7 @@

    Classes

    *, channel: str, post_at: Union[str, int], - text: str, + text: Optional[str] = None, as_user: Optional[bool] = None, attachments: Optional[Union[str, Sequence[Union[Dict, Attachment]]]] = None, blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, @@ -2811,6 +2838,7 @@

    Classes

    unfurl_media: Optional[bool] = None, link_names: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> Union[Future, SlackResponse]: """Schedules a message. @@ -2831,14 +2859,90 @@

    Classes

    "unfurl_media": unfurl_media, "link_names": link_names, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.scheduleMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.scheduleMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.scheduleMessage", json=kwargs) + def chat_scheduledMessages_list( + self, + *, + channel: Optional[str] = None, + cursor: Optional[str] = None, + latest: Optional[str] = None, + limit: Optional[int] = None, + oldest: Optional[str] = None, + team_id: Optional[str] = None, + **kwargs, + ) -> Union[Future, SlackResponse]: + """Lists all scheduled messages. + https://api.slack.com/methods/chat.scheduledMessages.list + """ + kwargs.update( + { + "channel": channel, + "cursor": cursor, + "latest": latest, + "limit": limit, + "oldest": oldest, + "team_id": team_id, + } + ) + return self.api_call("chat.scheduledMessages.list", params=kwargs) + + def chat_startStream( + self, + *, + channel: str, + thread_ts: Optional[str] = None, + markdown_text: Optional[str] = None, + unfurl_links: Optional[bool] = None, + unfurl_media: Optional[bool] = None, + **kwargs, + ) -> Union[Future, SlackResponse]: + """Starts a new streaming conversation. + https://api.slack.com/methods/chat.startStream + """ + kwargs.update( + { + "channel": channel, + "thread_ts": thread_ts, + "markdown_text": markdown_text, + "unfurl_links": unfurl_links, + "unfurl_media": unfurl_media, + } + ) + return self.api_call("chat.startStream", params=kwargs) + + def chat_stopStream( + self, + *, + channel: str, + ts: str, + markdown_text: Optional[str] = None, + blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, + metadata: Optional[Union[Dict, Metadata]] = None, + **kwargs, + ) -> Union[Future, SlackResponse]: + """Stops a streaming conversation. + https://api.slack.com/methods/chat.stopStream + """ + kwargs.update( + { + "channel": channel, + "ts": ts, + "markdown_text": markdown_text, + "blocks": blocks, + "metadata": metadata, + } + ) + _parse_web_class_objects(kwargs) + return self.api_call("chat.stopStream", params=kwargs) + def chat_unfurl( self, *, @@ -2888,6 +2992,7 @@

    Classes

    parse: Optional[str] = None, # none, full reply_broadcast: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> Union[Future, SlackResponse]: """Updates a message in a channel. @@ -2905,6 +3010,7 @@

    Classes

    "parse": parse, "reply_broadcast": reply_broadcast, "metadata": metadata, + "markdown_text": markdown_text, } ) if isinstance(file_ids, (list, tuple)): @@ -2913,36 +3019,10 @@

    Classes

    kwargs.update({"file_ids": file_ids}) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.update", kwargs) + _warn_if_message_text_content_is_missing("chat.update", kwargs) # NOTE: intentionally using json over params for API methods using blocks/attachments return self.api_call("chat.update", json=kwargs) - def chat_scheduledMessages_list( - self, - *, - channel: Optional[str] = None, - cursor: Optional[str] = None, - latest: Optional[str] = None, - limit: Optional[int] = None, - oldest: Optional[str] = None, - team_id: Optional[str] = None, - **kwargs, - ) -> Union[Future, SlackResponse]: - """Lists all scheduled messages. - https://api.slack.com/methods/chat.scheduledMessages.list - """ - kwargs.update( - { - "channel": channel, - "cursor": cursor, - "latest": latest, - "limit": limit, - "oldest": oldest, - "team_id": team_id, - } - ) - return self.api_call("chat.scheduledMessages.list", params=kwargs) - def conversations_acceptSharedInvite( self, *, @@ -5437,6 +5517,72 @@

    Classes

    # NOTE: Intentionally using json for the "view" parameter return self.api_call("views.publish", json=kwargs) + def workflows_featured_add( + self, + *, + channel_id: str, + trigger_ids: Union[str, Sequence[str]], + **kwargs, + ) -> Union[Future, SlackResponse]: + """Add featured workflows to a channel. + https://api.slack.com/methods/workflows.featured.add + """ + kwargs.update({"channel_id": channel_id}) + if isinstance(trigger_ids, (list, tuple)): + kwargs.update({"trigger_ids": ",".join(trigger_ids)}) + else: + kwargs.update({"trigger_ids": trigger_ids}) + return self.api_call("workflows.featured.add", params=kwargs) + + def workflows_featured_list( + self, + *, + channel_ids: Union[str, Sequence[str]], + **kwargs, + ) -> Union[Future, SlackResponse]: + """List the featured workflows for specified channels. + https://api.slack.com/methods/workflows.featured.list + """ + if isinstance(channel_ids, (list, tuple)): + kwargs.update({"channel_ids": ",".join(channel_ids)}) + else: + kwargs.update({"channel_ids": channel_ids}) + return self.api_call("workflows.featured.list", params=kwargs) + + def workflows_featured_remove( + self, + *, + channel_id: str, + trigger_ids: Union[str, Sequence[str]], + **kwargs, + ) -> Union[Future, SlackResponse]: + """Remove featured workflows from a channel. + https://api.slack.com/methods/workflows.featured.remove + """ + kwargs.update({"channel_id": channel_id}) + if isinstance(trigger_ids, (list, tuple)): + kwargs.update({"trigger_ids": ",".join(trigger_ids)}) + else: + kwargs.update({"trigger_ids": trigger_ids}) + return self.api_call("workflows.featured.remove", params=kwargs) + + def workflows_featured_set( + self, + *, + channel_id: str, + trigger_ids: Union[str, Sequence[str]], + **kwargs, + ) -> Union[Future, SlackResponse]: + """Set featured workflows for a channel. + https://api.slack.com/methods/workflows.featured.set + """ + kwargs.update({"channel_id": channel_id}) + if isinstance(trigger_ids, (list, tuple)): + kwargs.update({"trigger_ids": ",".join(trigger_ids)}) + else: + kwargs.update({"trigger_ids": trigger_ids}) + return self.api_call("workflows.featured.set", params=kwargs) + def workflows_stepCompleted( self, *, @@ -7914,7 +8060,7 @@

    Methods

    https://api.slack.com/methods/admin.users.invite

    -def admin_users_list(self,
    *,
    team_id: str,
    include_deactivated_user_workspaces: bool | None = None,
    is_active: bool | None = None,
    cursor: str | None = None,
    limit: int | None = None,
    **kwargs) ‑> _asyncio.Future | LegacySlackResponse
    +def admin_users_list(self,
    *,
    team_id: str | None = None,
    include_deactivated_user_workspaces: bool | None = None,
    is_active: bool | None = None,
    cursor: str | None = None,
    limit: int | None = None,
    **kwargs) ‑> _asyncio.Future | LegacySlackResponse
    @@ -7924,7 +8070,7 @@

    Methods

    def admin_users_list(
         self,
         *,
    -    team_id: str,
    +    team_id: Optional[str] = None,
         include_deactivated_user_workspaces: Optional[bool] = None,
         is_active: Optional[bool] = None,
         cursor: Optional[str] = None,
    @@ -8711,7 +8857,7 @@ 

    Methods

    https://api.slack.com/methods/apps.uninstall

    -def assistant_threads_setStatus(self, *, channel_id: str, thread_ts: str, status: str, **kwargs) ‑> _asyncio.Future | LegacySlackResponse +def assistant_threads_setStatus(self,
    *,
    channel_id: str,
    thread_ts: str,
    status: str,
    loading_messages: List[str] | None = None,
    **kwargs) ‑> _asyncio.Future | LegacySlackResponse
    @@ -8724,15 +8870,18 @@

    Methods

    channel_id: str, thread_ts: str, status: str, + loading_messages: Optional[List[str]] = None, **kwargs, ) -> Union[Future, SlackResponse]: - """Revokes a token. + """Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus """ - kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "status": status}) + kwargs.update( + {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} + ) return self.api_call("assistant.threads.setStatus", params=kwargs)
    -

    Revokes a token. +

    Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus

    @@ -8752,7 +8901,7 @@

    Methods

    prompts: List[Dict[str, str]], **kwargs, ) -> Union[Future, SlackResponse]: - """Revokes a token. + """Set suggested prompts for the given assistant thread. https://api.slack.com/methods/assistant.threads.setSuggestedPrompts """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "prompts": prompts}) @@ -8760,7 +8909,7 @@

    Methods

    kwargs.update({"title": title}) return self.api_call("assistant.threads.setSuggestedPrompts", json=kwargs)
    -

    Revokes a token. +

    Set suggested prompts for the given assistant thread. https://api.slack.com/methods/assistant.threads.setSuggestedPrompts

    @@ -8779,13 +8928,13 @@

    Methods

    title: str, **kwargs, ) -> Union[Future, SlackResponse]: - """Revokes a token. + """Set the title for the given assistant thread. https://api.slack.com/methods/assistant.threads.setTitle """ kwargs.update({"channel_id": channel_id, "thread_ts": thread_ts, "title": title}) return self.api_call("assistant.threads.setTitle", params=kwargs)
    -

    Revokes a token. +

    Set the title for the given assistant thread. https://api.slack.com/methods/assistant.threads.setTitle

    @@ -9656,6 +9805,37 @@

    Methods

    Unarchives a channel.

    +
    +def chat_appendStream(self, *, channel: str, ts: str, markdown_text: str, **kwargs) ‑> _asyncio.Future | LegacySlackResponse +
    +
    +
    + +Expand source code + +
    def chat_appendStream(
    +    self,
    +    *,
    +    channel: str,
    +    ts: str,
    +    markdown_text: str,
    +    **kwargs,
    +) -> Union[Future, SlackResponse]:
    +    """Appends text to an existing streaming conversation.
    +    https://api.slack.com/methods/chat.appendStream
    +    """
    +    kwargs.update(
    +        {
    +            "channel": channel,
    +            "ts": ts,
    +            "markdown_text": markdown_text,
    +        }
    +    )
    +    return self.api_call("chat.appendStream", params=kwargs)
    +
    +

    Appends text to an existing streaming conversation. +https://api.slack.com/methods/chat.appendStream

    +
    def chat_delete(self, *, channel: str, ts: str, as_user: bool | None = None, **kwargs) ‑> _asyncio.Future | LegacySlackResponse
    @@ -9761,7 +9941,7 @@

    Methods

    https://api.slack.com/methods/chat.meMessage

    -def chat_postEphemeral(self,
    *,
    channel: str,
    user: str,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    icon_emoji: str | None = None,
    icon_url: str | None = None,
    link_names: bool | None = None,
    username: str | None = None,
    parse: str | None = None,
    **kwargs) ‑> _asyncio.Future | LegacySlackResponse
    +def chat_postEphemeral(self,
    *,
    channel: str,
    user: str,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    icon_emoji: str | None = None,
    icon_url: str | None = None,
    link_names: bool | None = None,
    username: str | None = None,
    parse: str | None = None,
    markdown_text: str | None = None,
    **kwargs) ‑> _asyncio.Future | LegacySlackResponse
    @@ -9783,6 +9963,7 @@

    Methods

    link_names: Optional[bool] = None, username: Optional[str] = None, parse: Optional[str] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> Union[Future, SlackResponse]: """Sends an ephemeral message to a user in a channel. @@ -9802,11 +9983,12 @@

    Methods

    "link_names": link_names, "username": username, "parse": parse, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postEphemeral", kwargs) + _warn_if_message_text_content_is_missing("chat.postEphemeral", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.postEphemeral", json=kwargs)
    @@ -9814,7 +9996,7 @@

    Methods

    https://api.slack.com/methods/chat.postEphemeral

    -def chat_postMessage(self,
    *,
    channel: str,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    reply_broadcast: bool | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    container_id: str | None = None,
    icon_emoji: str | None = None,
    icon_url: str | None = None,
    mrkdwn: bool | None = None,
    link_names: bool | None = None,
    username: str | None = None,
    parse: str | None = None,
    metadata: Dict | Metadata | None = None,
    **kwargs) ‑> _asyncio.Future | LegacySlackResponse
    +def chat_postMessage(self,
    *,
    channel: str,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    reply_broadcast: bool | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    container_id: str | None = None,
    icon_emoji: str | None = None,
    icon_url: str | None = None,
    mrkdwn: bool | None = None,
    link_names: bool | None = None,
    username: str | None = None,
    parse: str | None = None,
    metadata: Dict | Metadata | None = None,
    markdown_text: str | None = None,
    **kwargs) ‑> _asyncio.Future | LegacySlackResponse
    @@ -9841,6 +10023,7 @@

    Methods

    username: Optional[str] = None, parse: Optional[str] = None, # none, full metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> Union[Future, SlackResponse]: """Sends a message to a channel. @@ -9865,11 +10048,12 @@

    Methods

    "username": username, "parse": parse, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.postMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.postMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.postMessage", json=kwargs)
    @@ -9877,7 +10061,7 @@

    Methods

    https://api.slack.com/methods/chat.postMessage

    -def chat_scheduleMessage(self,
    *,
    channel: str,
    post_at: str | int,
    text: str,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    parse: str | None = None,
    reply_broadcast: bool | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    link_names: bool | None = None,
    metadata: Dict | Metadata | None = None,
    **kwargs) ‑> _asyncio.Future | LegacySlackResponse
    +def chat_scheduleMessage(self,
    *,
    channel: str,
    post_at: str | int,
    text: str | None = None,
    as_user: bool | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    thread_ts: str | None = None,
    parse: str | None = None,
    reply_broadcast: bool | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    link_names: bool | None = None,
    metadata: Dict | Metadata | None = None,
    markdown_text: str | None = None,
    **kwargs) ‑> _asyncio.Future | LegacySlackResponse
    @@ -9889,7 +10073,7 @@

    Methods

    *, channel: str, post_at: Union[str, int], - text: str, + text: Optional[str] = None, as_user: Optional[bool] = None, attachments: Optional[Union[str, Sequence[Union[Dict, Attachment]]]] = None, blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, @@ -9900,6 +10084,7 @@

    Methods

    unfurl_media: Optional[bool] = None, link_names: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> Union[Future, SlackResponse]: """Schedules a message. @@ -9920,11 +10105,12 @@

    Methods

    "unfurl_media": unfurl_media, "link_names": link_names, "metadata": metadata, + "markdown_text": markdown_text, } ) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.scheduleMessage", kwargs) + _warn_if_message_text_content_is_missing("chat.scheduleMessage", kwargs) # NOTE: intentionally using json over params for the API methods using blocks/attachments return self.api_call("chat.scheduleMessage", json=kwargs)
    @@ -9968,6 +10154,77 @@

    Methods

    +
    +def chat_startStream(self,
    *,
    channel: str,
    thread_ts: str | None = None,
    markdown_text: str | None = None,
    unfurl_links: bool | None = None,
    unfurl_media: bool | None = None,
    **kwargs) ‑> _asyncio.Future | LegacySlackResponse
    +
    +
    +
    + +Expand source code + +
    def chat_startStream(
    +    self,
    +    *,
    +    channel: str,
    +    thread_ts: Optional[str] = None,
    +    markdown_text: Optional[str] = None,
    +    unfurl_links: Optional[bool] = None,
    +    unfurl_media: Optional[bool] = None,
    +    **kwargs,
    +) -> Union[Future, SlackResponse]:
    +    """Starts a new streaming conversation.
    +    https://api.slack.com/methods/chat.startStream
    +    """
    +    kwargs.update(
    +        {
    +            "channel": channel,
    +            "thread_ts": thread_ts,
    +            "markdown_text": markdown_text,
    +            "unfurl_links": unfurl_links,
    +            "unfurl_media": unfurl_media,
    +        }
    +    )
    +    return self.api_call("chat.startStream", params=kwargs)
    +
    +

    Starts a new streaming conversation. +https://api.slack.com/methods/chat.startStream

    +
    +
    +def chat_stopStream(self,
    *,
    channel: str,
    ts: str,
    markdown_text: str | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    metadata: Dict | Metadata | None = None,
    **kwargs) ‑> _asyncio.Future | LegacySlackResponse
    +
    +
    +
    + +Expand source code + +
    def chat_stopStream(
    +    self,
    +    *,
    +    channel: str,
    +    ts: str,
    +    markdown_text: Optional[str] = None,
    +    blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None,
    +    metadata: Optional[Union[Dict, Metadata]] = None,
    +    **kwargs,
    +) -> Union[Future, SlackResponse]:
    +    """Stops a streaming conversation.
    +    https://api.slack.com/methods/chat.stopStream
    +    """
    +    kwargs.update(
    +        {
    +            "channel": channel,
    +            "ts": ts,
    +            "markdown_text": markdown_text,
    +            "blocks": blocks,
    +            "metadata": metadata,
    +        }
    +    )
    +    _parse_web_class_objects(kwargs)
    +    return self.api_call("chat.stopStream", params=kwargs)
    +
    +

    Stops a streaming conversation. +https://api.slack.com/methods/chat.stopStream

    +
    def chat_unfurl(self,
    *,
    channel: str | None = None,
    ts: str | None = None,
    source: str | None = None,
    unfurl_id: str | None = None,
    unfurls: Dict[str, Dict] | None = None,
    user_auth_blocks: str | Sequence[Dict | Block] | None = None,
    user_auth_message: str | None = None,
    user_auth_required: bool | None = None,
    user_auth_url: str | None = None,
    **kwargs) ‑> _asyncio.Future | LegacySlackResponse
    @@ -10015,7 +10272,7 @@

    Methods

    https://api.slack.com/methods/chat.unfurl

    -def chat_update(self,
    *,
    channel: str,
    ts: str,
    text: str | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    as_user: bool | None = None,
    file_ids: str | Sequence[str] | None = None,
    link_names: bool | None = None,
    parse: str | None = None,
    reply_broadcast: bool | None = None,
    metadata: Dict | Metadata | None = None,
    **kwargs) ‑> _asyncio.Future | LegacySlackResponse
    +def chat_update(self,
    *,
    channel: str,
    ts: str,
    text: str | None = None,
    attachments: str | Sequence[Dict | Attachment] | None = None,
    blocks: str | Sequence[Dict | Block] | None = None,
    as_user: bool | None = None,
    file_ids: str | Sequence[str] | None = None,
    link_names: bool | None = None,
    parse: str | None = None,
    reply_broadcast: bool | None = None,
    metadata: Dict | Metadata | None = None,
    markdown_text: str | None = None,
    **kwargs) ‑> _asyncio.Future | LegacySlackResponse
    @@ -10036,6 +10293,7 @@

    Methods

    parse: Optional[str] = None, # none, full reply_broadcast: Optional[bool] = None, metadata: Optional[Union[Dict, Metadata]] = None, + markdown_text: Optional[str] = None, **kwargs, ) -> Union[Future, SlackResponse]: """Updates a message in a channel. @@ -10053,6 +10311,7 @@

    Methods

    "parse": parse, "reply_broadcast": reply_broadcast, "metadata": metadata, + "markdown_text": markdown_text, } ) if isinstance(file_ids, (list, tuple)): @@ -10061,7 +10320,7 @@

    Methods

    kwargs.update({"file_ids": file_ids}) _parse_web_class_objects(kwargs) kwargs = _remove_none_values(kwargs) - _warn_if_text_or_attachment_fallback_is_missing("chat.update", kwargs) + _warn_if_message_text_content_is_missing("chat.update", kwargs) # NOTE: intentionally using json over params for API methods using blocks/attachments return self.api_call("chat.update", json=kwargs)
    @@ -14089,6 +14348,116 @@

    Methods

    to learn more about updating views and avoiding race conditions with the hash argument. https://api.slack.com/methods/views.update

    + +
    +
    + +Expand source code + +
    def workflows_featured_add(
    +    self,
    +    *,
    +    channel_id: str,
    +    trigger_ids: Union[str, Sequence[str]],
    +    **kwargs,
    +) -> Union[Future, SlackResponse]:
    +    """Add featured workflows to a channel.
    +    https://api.slack.com/methods/workflows.featured.add
    +    """
    +    kwargs.update({"channel_id": channel_id})
    +    if isinstance(trigger_ids, (list, tuple)):
    +        kwargs.update({"trigger_ids": ",".join(trigger_ids)})
    +    else:
    +        kwargs.update({"trigger_ids": trigger_ids})
    +    return self.api_call("workflows.featured.add", params=kwargs)
    +
    +

    Add featured workflows to a channel. +https://api.slack.com/methods/workflows.featured.add

    +
    + +
    +
    + +Expand source code + +
    def workflows_featured_list(
    +    self,
    +    *,
    +    channel_ids: Union[str, Sequence[str]],
    +    **kwargs,
    +) -> Union[Future, SlackResponse]:
    +    """List the featured workflows for specified channels.
    +    https://api.slack.com/methods/workflows.featured.list
    +    """
    +    if isinstance(channel_ids, (list, tuple)):
    +        kwargs.update({"channel_ids": ",".join(channel_ids)})
    +    else:
    +        kwargs.update({"channel_ids": channel_ids})
    +    return self.api_call("workflows.featured.list", params=kwargs)
    +
    +

    List the featured workflows for specified channels. +https://api.slack.com/methods/workflows.featured.list

    +
    + +
    +
    + +Expand source code + +
    def workflows_featured_remove(
    +    self,
    +    *,
    +    channel_id: str,
    +    trigger_ids: Union[str, Sequence[str]],
    +    **kwargs,
    +) -> Union[Future, SlackResponse]:
    +    """Remove featured workflows from a channel.
    +    https://api.slack.com/methods/workflows.featured.remove
    +    """
    +    kwargs.update({"channel_id": channel_id})
    +    if isinstance(trigger_ids, (list, tuple)):
    +        kwargs.update({"trigger_ids": ",".join(trigger_ids)})
    +    else:
    +        kwargs.update({"trigger_ids": trigger_ids})
    +    return self.api_call("workflows.featured.remove", params=kwargs)
    +
    +

    Remove featured workflows from a channel. +https://api.slack.com/methods/workflows.featured.remove

    +
    + +
    +
    + +Expand source code + +
    def workflows_featured_set(
    +    self,
    +    *,
    +    channel_id: str,
    +    trigger_ids: Union[str, Sequence[str]],
    +    **kwargs,
    +) -> Union[Future, SlackResponse]:
    +    """Set featured workflows for a channel.
    +    https://api.slack.com/methods/workflows.featured.set
    +    """
    +    kwargs.update({"channel_id": channel_id})
    +    if isinstance(trigger_ids, (list, tuple)):
    +        kwargs.update({"trigger_ids": ",".join(trigger_ids)})
    +    else:
    +        kwargs.update({"trigger_ids": trigger_ids})
    +    return self.api_call("workflows.featured.set", params=kwargs)
    +
    +

    Set featured workflows for a channel. +https://api.slack.com/methods/workflows.featured.set

    +
    def workflows_stepCompleted(self, *, workflow_step_execute_id: str, outputs: dict | None = None, **kwargs) ‑> _asyncio.Future | LegacySlackResponse
    @@ -14360,6 +14729,7 @@

    channels_setPurpose
  • channels_setTopic
  • channels_unarchive
  • +
  • chat_appendStream
  • chat_delete
  • chat_deleteScheduledMessage
  • chat_getPermalink
  • @@ -14368,6 +14738,8 @@

    chat_postMessage
  • chat_scheduleMessage
  • chat_scheduledMessages_list
  • +
  • chat_startStream
  • +
  • chat_stopStream
  • chat_unfurl
  • chat_update
  • conversations_acceptSharedInvite
  • @@ -14510,6 +14882,10 @@

    views_publish
  • views_push
  • views_update
  • +
  • workflows_featured_add
  • +
  • workflows_featured_list
  • +
  • workflows_featured_remove
  • +
  • workflows_featured_set
  • workflows_stepCompleted
  • workflows_stepFailed
  • workflows_updateStep
  • diff --git a/docs/reference/webhook/client.html b/docs/reference/webhook/client.html index 6400d63d6..5ff5a4c5b 100644 --- a/docs/reference/webhook/client.html +++ b/docs/reference/webhook/client.html @@ -297,13 +297,13 @@

    Classes

    http_resp = opener.open(req, timeout=self.timeout) else: http_resp = urlopen(req, context=self.ssl, timeout=self.timeout) - charset: str = http_resp.headers.get_content_charset() or "utf-8" # type: ignore[union-attr] - response_body: str = http_resp.read().decode(charset) # type: ignore[union-attr] + charset: str = http_resp.headers.get_content_charset() or "utf-8" + response_body: str = http_resp.read().decode(charset) resp = WebhookResponse( url=url, - status_code=http_resp.status, # type: ignore[union-attr] + status_code=http_resp.status, body=response_body, - headers=http_resp.headers, # type: ignore[arg-type, union-attr] + headers=http_resp.headers, # type: ignore[arg-type] ) _debug_log_response(self.logger, resp) return resp
    diff --git a/docs/reference/webhook/index.html b/docs/reference/webhook/index.html index 31f7a7e40..937313a13 100644 --- a/docs/reference/webhook/index.html +++ b/docs/reference/webhook/index.html @@ -319,13 +319,13 @@

    Classes

    http_resp = opener.open(req, timeout=self.timeout) else: http_resp = urlopen(req, context=self.ssl, timeout=self.timeout) - charset: str = http_resp.headers.get_content_charset() or "utf-8" # type: ignore[union-attr] - response_body: str = http_resp.read().decode(charset) # type: ignore[union-attr] + charset: str = http_resp.headers.get_content_charset() or "utf-8" + response_body: str = http_resp.read().decode(charset) resp = WebhookResponse( url=url, - status_code=http_resp.status, # type: ignore[union-attr] + status_code=http_resp.status, body=response_body, - headers=http_resp.headers, # type: ignore[arg-type, union-attr] + headers=http_resp.headers, # type: ignore[arg-type] ) _debug_log_response(self.logger, resp) return resp
    diff --git a/slack_sdk/version.py b/slack_sdk/version.py index a38bbbbbf..7063072ba 100644 --- a/slack_sdk/version.py +++ b/slack_sdk/version.py @@ -1,3 +1,3 @@ """Check the latest version at https://pypi.org/project/slack-sdk/""" -__version__ = "3.36.0" +__version__ = "3.36.0.dev0" From 16741f824feec0ccb2b136361ddefe64a7cacb68 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Mon, 22 Sep 2025 21:51:12 -0700 Subject: [PATCH 04/21] fix(web-api): use json content type for chat stream methods (#1749) --- slack_sdk/web/async_client.py | 9 ++++++--- slack_sdk/web/client.py | 9 ++++++--- slack_sdk/web/legacy_client.py | 9 ++++++--- tests/slack_sdk_async/web/test_web_client_coverage.py | 6 ++++-- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/slack_sdk/web/async_client.py b/slack_sdk/web/async_client.py index 0c047892a..3894cbfa3 100644 --- a/slack_sdk/web/async_client.py +++ b/slack_sdk/web/async_client.py @@ -2641,7 +2641,8 @@ async def chat_appendStream( "markdown_text": markdown_text, } ) - return await self.api_call("chat.appendStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return await self.api_call("chat.appendStream", json=kwargs) async def chat_delete( self, @@ -2895,7 +2896,8 @@ async def chat_startStream( "unfurl_media": unfurl_media, } ) - return await self.api_call("chat.startStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return await self.api_call("chat.startStream", json=kwargs) async def chat_stopStream( self, @@ -2920,7 +2922,8 @@ async def chat_stopStream( } ) _parse_web_class_objects(kwargs) - return await self.api_call("chat.stopStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return await self.api_call("chat.stopStream", json=kwargs) async def chat_unfurl( self, diff --git a/slack_sdk/web/client.py b/slack_sdk/web/client.py index 9ff9eeb66..3314e336d 100644 --- a/slack_sdk/web/client.py +++ b/slack_sdk/web/client.py @@ -2631,7 +2631,8 @@ def chat_appendStream( "markdown_text": markdown_text, } ) - return self.api_call("chat.appendStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.appendStream", json=kwargs) def chat_delete( self, @@ -2885,7 +2886,8 @@ def chat_startStream( "unfurl_media": unfurl_media, } ) - return self.api_call("chat.startStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.startStream", json=kwargs) def chat_stopStream( self, @@ -2910,7 +2912,8 @@ def chat_stopStream( } ) _parse_web_class_objects(kwargs) - return self.api_call("chat.stopStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.stopStream", json=kwargs) def chat_unfurl( self, diff --git a/slack_sdk/web/legacy_client.py b/slack_sdk/web/legacy_client.py index e83f82a1a..385f1839a 100644 --- a/slack_sdk/web/legacy_client.py +++ b/slack_sdk/web/legacy_client.py @@ -2643,7 +2643,8 @@ def chat_appendStream( "markdown_text": markdown_text, } ) - return self.api_call("chat.appendStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.appendStream", json=kwargs) def chat_delete( self, @@ -2897,7 +2898,8 @@ def chat_startStream( "unfurl_media": unfurl_media, } ) - return self.api_call("chat.startStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.startStream", json=kwargs) def chat_stopStream( self, @@ -2922,7 +2924,8 @@ def chat_stopStream( } ) _parse_web_class_objects(kwargs) - return self.api_call("chat.stopStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.stopStream", json=kwargs) def chat_unfurl( self, diff --git a/tests/slack_sdk_async/web/test_web_client_coverage.py b/tests/slack_sdk_async/web/test_web_client_coverage.py index 3900e34a2..a335f5ded 100644 --- a/tests/slack_sdk_async/web/test_web_client_coverage.py +++ b/tests/slack_sdk_async/web/test_web_client_coverage.py @@ -571,8 +571,10 @@ async def run_method(self, method_name, method, async_method): self.api_methods_to_call.remove(method(channel="C123")["method"]) await async_method(channel="C123") elif method_name == "chat_stopStream": - self.api_methods_to_call.remove(method(channel="C123", ts="123.123")["method"]) - await async_method(channel="C123", ts="123.123") + self.api_methods_to_call.remove( + method(channel="C123", ts="123.123", blocks=[{"type": "markdown", "text": "**twelve**"}])["method"] + ) + await async_method(channel="C123", ts="123.123", blocks=[{"type": "markdown", "text": "**twelve**"}]) elif method_name == "chat_unfurl": self.api_methods_to_call.remove( method( From 551e379b72f789cb3f8743245160c283f73f7069 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 23 Sep 2025 10:09:05 -0700 Subject: [PATCH 05/21] chore(release): version 3.36.0.dev1 --- docs/reference/index.html | 18 ++-- docs/reference/models/blocks/blocks.html | 118 +++++++++++++++++++++++ docs/reference/models/blocks/index.html | 118 +++++++++++++++++++++++ docs/reference/web/async_client.html | 18 ++-- docs/reference/web/client.html | 18 ++-- docs/reference/web/index.html | 18 ++-- docs/reference/web/legacy_client.html | 18 ++-- slack_sdk/version.py | 2 +- 8 files changed, 297 insertions(+), 31 deletions(-) diff --git a/docs/reference/index.html b/docs/reference/index.html index f9829dfc4..b3d150db9 100644 --- a/docs/reference/index.html +++ b/docs/reference/index.html @@ -2767,7 +2767,8 @@

    Classes

    "markdown_text": markdown_text, } ) - return self.api_call("chat.appendStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.appendStream", json=kwargs) def chat_delete( self, @@ -3021,7 +3022,8 @@

    Classes

    "unfurl_media": unfurl_media, } ) - return self.api_call("chat.startStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.startStream", json=kwargs) def chat_stopStream( self, @@ -3046,7 +3048,8 @@

    Classes

    } ) _parse_web_class_objects(kwargs) - return self.api_call("chat.stopStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.stopStream", json=kwargs) def chat_unfurl( self, @@ -9936,7 +9939,8 @@

    Methods

    "markdown_text": markdown_text, } ) - return self.api_call("chat.appendStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.appendStream", json=kwargs)

    Appends text to an existing streaming conversation. https://api.slack.com/methods/chat.appendStream

    @@ -10289,7 +10293,8 @@

    Methods

    "unfurl_media": unfurl_media, } ) - return self.api_call("chat.startStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.startStream", json=kwargs)

    Starts a new streaming conversation. https://api.slack.com/methods/chat.startStream

    @@ -10325,7 +10330,8 @@

    Methods

    } ) _parse_web_class_objects(kwargs) - return self.api_call("chat.stopStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.stopStream", json=kwargs)

    Stops a streaming conversation. https://api.slack.com/methods/chat.stopStream

    diff --git a/docs/reference/models/blocks/blocks.html b/docs/reference/models/blocks/blocks.html index a995554f4..efb2e41ab 100644 --- a/docs/reference/models/blocks/blocks.html +++ b/docs/reference/models/blocks/blocks.html @@ -228,6 +228,8 @@

    Inherited members

    return CallBlock(**block) elif type == HeaderBlock.type: return HeaderBlock(**block) + elif type == MarkdownBlock.type: + return MarkdownBlock(**block) elif type == VideoBlock.type: return VideoBlock(**block) elif type == RichTextBlock.type: @@ -261,6 +263,7 @@

    Subclasses

  • HeaderBlock
  • ImageBlock
  • InputBlock
  • +
  • MarkdownBlock
  • RichTextBlock
  • SectionBlock
  • VideoBlock
  • @@ -1098,6 +1101,113 @@

    Inherited members

    +
    +class MarkdownBlock +(*, text: str, block_id: str | None = None, **others: dict) +
    +
    +
    + +Expand source code + +
    class MarkdownBlock(Block):
    +    type = "markdown"
    +    text_max_length = 12000
    +
    +    @property
    +    def attributes(self) -> Set[str]:  # type: ignore[override]
    +        return super().attributes.union({"text"})
    +
    +    def __init__(
    +        self,
    +        *,
    +        text: str,
    +        block_id: Optional[str] = None,
    +        **others: dict,
    +    ):
    +        """Displays formatted markdown.
    +        https://docs.slack.dev/reference/block-kit/blocks/markdown-block/
    +
    +        Args:
    +            block_id: A string acting as a unique identifier for a block. If not specified, one will be generated.
    +                Maximum length for this field is 255 characters.
    +                block_id should be unique for each message and each iteration of a message.
    +                If a message is updated, use a new block_id.
    +            text (required): The standard markdown-formatted text. Limit 12,000 characters max.
    +        """
    +        super().__init__(type=self.type, block_id=block_id)
    +        show_unknown_key_warning(self, others)
    +
    +        self.text = text
    +
    +    @JsonValidator("text attribute must be specified")
    +    def _validate_text(self):
    +        return self.text != ""
    +
    +    @JsonValidator(f"text attribute cannot exceed {text_max_length} characters")
    +    def _validate_alt_text_length(self):
    +        return len(self.text) <= self.text_max_length
    +
    +

    Blocks are a series of components that can be combined +to create visually rich and compellingly interactive messages. +https://api.slack.com/reference/block-kit/blocks

    +

    Displays formatted markdown. +https://docs.slack.dev/reference/block-kit/blocks/markdown-block/

    +

    Args

    +
    +
    block_id
    +
    A string acting as a unique identifier for a block. If not specified, one will be generated. +Maximum length for this field is 255 characters. +block_id should be unique for each message and each iteration of a message. +If a message is updated, use a new block_id.
    +
    text : required
    +
    The standard markdown-formatted text. Limit 12,000 characters max.
    +
    +

    Ancestors

    + +

    Class variables

    +
    +
    var text_max_length
    +
    +

    The type of the None singleton.

    +
    +
    var type
    +
    +

    The type of the None singleton.

    +
    +
    +

    Instance variables

    +
    +
    prop attributes : Set[str]
    +
    +
    + +Expand source code + +
    @property
    +def attributes(self) -> Set[str]:  # type: ignore[override]
    +    return super().attributes.union({"text"})
    +
    +

    Build an unordered collection of unique elements.

    +
    +
    +

    Inherited members

    + +
    class RichTextBlock (*,
    elements: Sequence[dict | RichTextElement],
    block_id: str | None = None,
    **others: dict)
    @@ -1652,6 +1762,14 @@

    MarkdownBlock

    + + +
  • RichTextBlock

    • attributes
    • diff --git a/docs/reference/models/blocks/index.html b/docs/reference/models/blocks/index.html index 97d9b5294..7a69ec6e6 100644 --- a/docs/reference/models/blocks/index.html +++ b/docs/reference/models/blocks/index.html @@ -250,6 +250,8 @@

      Inherited members

      return CallBlock(**block) elif type == HeaderBlock.type: return HeaderBlock(**block) + elif type == MarkdownBlock.type: + return MarkdownBlock(**block) elif type == VideoBlock.type: return VideoBlock(**block) elif type == RichTextBlock.type: @@ -283,6 +285,7 @@

      Subclasses

    • HeaderBlock
    • ImageBlock
    • InputBlock
    • +
    • MarkdownBlock
    • RichTextBlock
    • SectionBlock
    • VideoBlock
    • @@ -3579,6 +3582,113 @@

      Inherited members

    +
    +class MarkdownBlock +(*, text: str, block_id: str | None = None, **others: dict) +
    +
    +
    + +Expand source code + +
    class MarkdownBlock(Block):
    +    type = "markdown"
    +    text_max_length = 12000
    +
    +    @property
    +    def attributes(self) -> Set[str]:  # type: ignore[override]
    +        return super().attributes.union({"text"})
    +
    +    def __init__(
    +        self,
    +        *,
    +        text: str,
    +        block_id: Optional[str] = None,
    +        **others: dict,
    +    ):
    +        """Displays formatted markdown.
    +        https://docs.slack.dev/reference/block-kit/blocks/markdown-block/
    +
    +        Args:
    +            block_id: A string acting as a unique identifier for a block. If not specified, one will be generated.
    +                Maximum length for this field is 255 characters.
    +                block_id should be unique for each message and each iteration of a message.
    +                If a message is updated, use a new block_id.
    +            text (required): The standard markdown-formatted text. Limit 12,000 characters max.
    +        """
    +        super().__init__(type=self.type, block_id=block_id)
    +        show_unknown_key_warning(self, others)
    +
    +        self.text = text
    +
    +    @JsonValidator("text attribute must be specified")
    +    def _validate_text(self):
    +        return self.text != ""
    +
    +    @JsonValidator(f"text attribute cannot exceed {text_max_length} characters")
    +    def _validate_alt_text_length(self):
    +        return len(self.text) <= self.text_max_length
    +
    +

    Blocks are a series of components that can be combined +to create visually rich and compellingly interactive messages. +https://api.slack.com/reference/block-kit/blocks

    +

    Displays formatted markdown. +https://docs.slack.dev/reference/block-kit/blocks/markdown-block/

    +

    Args

    +
    +
    block_id
    +
    A string acting as a unique identifier for a block. If not specified, one will be generated. +Maximum length for this field is 255 characters. +block_id should be unique for each message and each iteration of a message. +If a message is updated, use a new block_id.
    +
    text : required
    +
    The standard markdown-formatted text. Limit 12,000 characters max.
    +
    +

    Ancestors

    + +

    Class variables

    +
    +
    var text_max_length
    +
    +

    The type of the None singleton.

    +
    +
    var type
    +
    +

    The type of the None singleton.

    +
    +
    +

    Instance variables

    +
    +
    prop attributes : Set[str]
    +
    +
    + +Expand source code + +
    @property
    +def attributes(self) -> Set[str]:  # type: ignore[override]
    +    return super().attributes.union({"text"})
    +
    +

    Build an unordered collection of unique elements.

    +
    +
    +

    Inherited members

    + +
    class MarkdownTextObject (*, text: str, verbatim: bool | None = None) @@ -7465,6 +7575,14 @@

    LinkButtonElement

  • +

    MarkdownBlock

    + +
  • +
  • MarkdownTextObject

    • attributes
    • diff --git a/docs/reference/web/async_client.html b/docs/reference/web/async_client.html index ab5c0ab98..3ae302e59 100644 --- a/docs/reference/web/async_client.html +++ b/docs/reference/web/async_client.html @@ -2663,7 +2663,8 @@

      Classes

      "markdown_text": markdown_text, } ) - return await self.api_call("chat.appendStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return await self.api_call("chat.appendStream", json=kwargs) async def chat_delete( self, @@ -2917,7 +2918,8 @@

      Classes

      "unfurl_media": unfurl_media, } ) - return await self.api_call("chat.startStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return await self.api_call("chat.startStream", json=kwargs) async def chat_stopStream( self, @@ -2942,7 +2944,8 @@

      Classes

      } ) _parse_web_class_objects(kwargs) - return await self.api_call("chat.stopStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return await self.api_call("chat.stopStream", json=kwargs) async def chat_unfurl( self, @@ -9832,7 +9835,8 @@

      Methods

      "markdown_text": markdown_text, } ) - return await self.api_call("chat.appendStream", params=kwargs)
      + kwargs = _remove_none_values(kwargs) + return await self.api_call("chat.appendStream", json=kwargs)

      Appends text to an existing streaming conversation. https://api.slack.com/methods/chat.appendStream

      @@ -10185,7 +10189,8 @@

      Methods

      "unfurl_media": unfurl_media, } ) - return await self.api_call("chat.startStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return await self.api_call("chat.startStream", json=kwargs)

      Starts a new streaming conversation. https://api.slack.com/methods/chat.startStream

      @@ -10221,7 +10226,8 @@

      Methods

      } ) _parse_web_class_objects(kwargs) - return await self.api_call("chat.stopStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return await self.api_call("chat.stopStream", json=kwargs)

      Stops a streaming conversation. https://api.slack.com/methods/chat.stopStream

      diff --git a/docs/reference/web/client.html b/docs/reference/web/client.html index 9e743c5b8..12ddbb35d 100644 --- a/docs/reference/web/client.html +++ b/docs/reference/web/client.html @@ -2663,7 +2663,8 @@

      Classes

      "markdown_text": markdown_text, } ) - return self.api_call("chat.appendStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.appendStream", json=kwargs) def chat_delete( self, @@ -2917,7 +2918,8 @@

      Classes

      "unfurl_media": unfurl_media, } ) - return self.api_call("chat.startStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.startStream", json=kwargs) def chat_stopStream( self, @@ -2942,7 +2944,8 @@

      Classes

      } ) _parse_web_class_objects(kwargs) - return self.api_call("chat.stopStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.stopStream", json=kwargs) def chat_unfurl( self, @@ -9832,7 +9835,8 @@

      Methods

      "markdown_text": markdown_text, } ) - return self.api_call("chat.appendStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.appendStream", json=kwargs)

      Appends text to an existing streaming conversation. https://api.slack.com/methods/chat.appendStream

      @@ -10185,7 +10189,8 @@

      Methods

      "unfurl_media": unfurl_media, } ) - return self.api_call("chat.startStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.startStream", json=kwargs)

      Starts a new streaming conversation. https://api.slack.com/methods/chat.startStream

      @@ -10221,7 +10226,8 @@

      Methods

      } ) _parse_web_class_objects(kwargs) - return self.api_call("chat.stopStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.stopStream", json=kwargs)

      Stops a streaming conversation. https://api.slack.com/methods/chat.stopStream

      diff --git a/docs/reference/web/index.html b/docs/reference/web/index.html index 27a78aa62..bcee3c7ae 100644 --- a/docs/reference/web/index.html +++ b/docs/reference/web/index.html @@ -3024,7 +3024,8 @@

      Raises

      "markdown_text": markdown_text, } ) - return self.api_call("chat.appendStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.appendStream", json=kwargs) def chat_delete( self, @@ -3278,7 +3279,8 @@

      Raises

      "unfurl_media": unfurl_media, } ) - return self.api_call("chat.startStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.startStream", json=kwargs) def chat_stopStream( self, @@ -3303,7 +3305,8 @@

      Raises

      } ) _parse_web_class_objects(kwargs) - return self.api_call("chat.stopStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.stopStream", json=kwargs) def chat_unfurl( self, @@ -10193,7 +10196,8 @@

      Methods

      "markdown_text": markdown_text, } ) - return self.api_call("chat.appendStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.appendStream", json=kwargs)

      Appends text to an existing streaming conversation. https://api.slack.com/methods/chat.appendStream

      @@ -10546,7 +10550,8 @@

      Methods

      "unfurl_media": unfurl_media, } ) - return self.api_call("chat.startStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.startStream", json=kwargs)

      Starts a new streaming conversation. https://api.slack.com/methods/chat.startStream

      @@ -10582,7 +10587,8 @@

      Methods

      } ) _parse_web_class_objects(kwargs) - return self.api_call("chat.stopStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.stopStream", json=kwargs)

      Stops a streaming conversation. https://api.slack.com/methods/chat.stopStream

      diff --git a/docs/reference/web/legacy_client.html b/docs/reference/web/legacy_client.html index 37497b948..578ce8058 100644 --- a/docs/reference/web/legacy_client.html +++ b/docs/reference/web/legacy_client.html @@ -2662,7 +2662,8 @@

      Classes

      "markdown_text": markdown_text, } ) - return self.api_call("chat.appendStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.appendStream", json=kwargs) def chat_delete( self, @@ -2916,7 +2917,8 @@

      Classes

      "unfurl_media": unfurl_media, } ) - return self.api_call("chat.startStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.startStream", json=kwargs) def chat_stopStream( self, @@ -2941,7 +2943,8 @@

      Classes

      } ) _parse_web_class_objects(kwargs) - return self.api_call("chat.stopStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.stopStream", json=kwargs) def chat_unfurl( self, @@ -9831,7 +9834,8 @@

      Methods

      "markdown_text": markdown_text, } ) - return self.api_call("chat.appendStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.appendStream", json=kwargs)

      Appends text to an existing streaming conversation. https://api.slack.com/methods/chat.appendStream

      @@ -10184,7 +10188,8 @@

      Methods

      "unfurl_media": unfurl_media, } ) - return self.api_call("chat.startStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.startStream", json=kwargs)

      Starts a new streaming conversation. https://api.slack.com/methods/chat.startStream

      @@ -10220,7 +10225,8 @@

      Methods

      } ) _parse_web_class_objects(kwargs) - return self.api_call("chat.stopStream", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("chat.stopStream", json=kwargs)

      Stops a streaming conversation. https://api.slack.com/methods/chat.stopStream

      diff --git a/slack_sdk/version.py b/slack_sdk/version.py index 7063072ba..db6975baf 100644 --- a/slack_sdk/version.py +++ b/slack_sdk/version.py @@ -1,3 +1,3 @@ """Check the latest version at https://pypi.org/project/slack-sdk/""" -__version__ = "3.36.0.dev0" +__version__ = "3.36.0.dev1" From d335831c163eb8d3a9d2166ab4e0ebf97fee156b Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 23 Sep 2025 16:18:24 -0700 Subject: [PATCH 06/21] feat(models): add feedback_buttons and icon_button blocks as context_actions block elements (#1750) --- slack_sdk/models/blocks/__init__.py | 127 +++++++++++--------- slack_sdk/models/blocks/basic_components.py | 67 ++++++++++- slack_sdk/models/blocks/block_elements.py | 119 +++++++++++++++--- slack_sdk/models/blocks/blocks.py | 64 ++++++++-- tests/slack_sdk/models/test_blocks.py | 82 ++++++++++--- tests/slack_sdk/models/test_elements.py | 106 ++++++++++++---- tests/slack_sdk/models/test_objects.py | 76 +++++++++--- 7 files changed, 499 insertions(+), 142 deletions(-) diff --git a/slack_sdk/models/blocks/__init__.py b/slack_sdk/models/blocks/__init__.py index 455d28d5c..dbb8b5177 100644 --- a/slack_sdk/models/blocks/__init__.py +++ b/slack_sdk/models/blocks/__init__.py @@ -6,67 +6,79 @@ * https://api.slack.com/reference/block-kit/blocks * https://app.slack.com/block-kit-builder """ -from .basic_components import ButtonStyles -from .basic_components import ConfirmObject -from .basic_components import DynamicSelectElementTypes -from .basic_components import MarkdownTextObject -from .basic_components import Option -from .basic_components import OptionGroup -from .basic_components import PlainTextObject -from .basic_components import TextObject -from .block_elements import BlockElement -from .block_elements import ButtonElement -from .block_elements import ChannelMultiSelectElement -from .block_elements import ChannelSelectElement -from .block_elements import CheckboxesElement -from .block_elements import ConversationFilter -from .block_elements import ConversationMultiSelectElement -from .block_elements import ConversationSelectElement -from .block_elements import DatePickerElement -from .block_elements import TimePickerElement -from .block_elements import DateTimePickerElement -from .block_elements import ExternalDataMultiSelectElement -from .block_elements import ExternalDataSelectElement -from .block_elements import ImageElement -from .block_elements import InputInteractiveElement -from .block_elements import InteractiveElement -from .block_elements import LinkButtonElement -from .block_elements import OverflowMenuElement -from .block_elements import RichTextInputElement -from .block_elements import PlainTextInputElement -from .block_elements import EmailInputElement -from .block_elements import UrlInputElement -from .block_elements import NumberInputElement -from .block_elements import RadioButtonsElement -from .block_elements import SelectElement -from .block_elements import StaticMultiSelectElement -from .block_elements import StaticSelectElement -from .block_elements import UserMultiSelectElement -from .block_elements import UserSelectElement -from .block_elements import RichTextElement -from .block_elements import RichTextElementParts -from .block_elements import RichTextListElement -from .block_elements import RichTextPreformattedElement -from .block_elements import RichTextQuoteElement -from .block_elements import RichTextSectionElement -from .blocks import ActionsBlock -from .blocks import Block -from .blocks import CallBlock -from .blocks import ContextBlock -from .blocks import DividerBlock -from .blocks import FileBlock -from .blocks import HeaderBlock -from .blocks import ImageBlock -from .blocks import InputBlock -from .blocks import MarkdownBlock -from .blocks import SectionBlock -from .blocks import VideoBlock -from .blocks import RichTextBlock + +from .basic_components import ( + ButtonStyles, + ConfirmObject, + DynamicSelectElementTypes, + FeedbackButtonObject, + MarkdownTextObject, + Option, + OptionGroup, + PlainTextObject, + TextObject, +) +from .block_elements import ( + BlockElement, + ButtonElement, + ChannelMultiSelectElement, + ChannelSelectElement, + CheckboxesElement, + ConversationFilter, + ConversationMultiSelectElement, + ConversationSelectElement, + DatePickerElement, + DateTimePickerElement, + EmailInputElement, + ExternalDataMultiSelectElement, + ExternalDataSelectElement, + FeedbackButtonsElement, + IconButtonElement, + ImageElement, + InputInteractiveElement, + InteractiveElement, + LinkButtonElement, + NumberInputElement, + OverflowMenuElement, + PlainTextInputElement, + RadioButtonsElement, + RichTextElement, + RichTextElementParts, + RichTextInputElement, + RichTextListElement, + RichTextPreformattedElement, + RichTextQuoteElement, + RichTextSectionElement, + SelectElement, + StaticMultiSelectElement, + StaticSelectElement, + TimePickerElement, + UrlInputElement, + UserMultiSelectElement, + UserSelectElement, +) +from .blocks import ( + ActionsBlock, + Block, + CallBlock, + ContextActionsBlock, + ContextBlock, + DividerBlock, + FileBlock, + HeaderBlock, + ImageBlock, + InputBlock, + MarkdownBlock, + RichTextBlock, + SectionBlock, + VideoBlock, +) __all__ = [ "ButtonStyles", "ConfirmObject", "DynamicSelectElementTypes", + "FeedbackButtonObject", "MarkdownTextObject", "Option", "OptionGroup", @@ -85,6 +97,8 @@ "DateTimePickerElement", "ExternalDataMultiSelectElement", "ExternalDataSelectElement", + "FeedbackButtonsElement", + "IconButtonElement", "ImageElement", "InputInteractiveElement", "InteractiveElement", @@ -110,6 +124,7 @@ "ActionsBlock", "Block", "CallBlock", + "ContextActionsBlock", "ContextBlock", "DividerBlock", "FileBlock", diff --git a/slack_sdk/models/blocks/basic_components.py b/slack_sdk/models/blocks/basic_components.py index d6a1aed97..ba3de57a4 100644 --- a/slack_sdk/models/blocks/basic_components.py +++ b/slack_sdk/models/blocks/basic_components.py @@ -1,13 +1,10 @@ import copy import logging import warnings -from typing import List, Optional, Set, Union, Sequence, Dict, Any +from typing import Any, Dict, List, Optional, Sequence, Set, Union from slack_sdk.models import show_unknown_key_warning -from slack_sdk.models.basic_objects import ( - JsonObject, - JsonValidator, -) +from slack_sdk.models.basic_objects import JsonObject, JsonValidator from slack_sdk.models.messages import Link ButtonStyles = {"danger", "primary"} @@ -526,6 +523,66 @@ def to_dict(self) -> Dict[str, Any]: return json +class FeedbackButtonObject(JsonObject): + attributes: Set[str] = set() + + text_max_length = 75 + value_max_length = 2000 + + @classmethod + def parse(cls, feedback_button: Union["FeedbackButtonObject", Dict[str, Any]]): + if feedback_button: + if isinstance(feedback_button, FeedbackButtonObject): + return feedback_button + elif isinstance(feedback_button, dict): + return FeedbackButtonObject(**feedback_button) + else: + # Not yet implemented: show some warning here + return None + return None + + def __init__( + self, + *, + text: Union[str, Dict[str, Any], PlainTextObject], + accessibility_label: Optional[str] = None, + value: str, + **others: Dict[str, Any], + ): + """ + A feedback button element object for either positive or negative feedback. + + Args: + text (required): An object containing some text. Maximum length for this field is 75 characters. + accessibility_label: A label for longer descriptive text about a button element. This label will be read out by + screen readers instead of the button `text` object. + value (required): The button value. Maximum length for this field is 2000 characters. + """ + self._text: Optional[TextObject] = PlainTextObject.parse(text, default_type=PlainTextObject.type) + self._accessibility_label: Optional[str] = accessibility_label + self._value: Optional[str] = value + show_unknown_key_warning(self, others) + + @JsonValidator(f"text attribute cannot exceed {text_max_length} characters") + def text_length(self) -> bool: + return self._text is None or len(self._text.text) <= self.text_max_length + + @JsonValidator(f"value attribute cannot exceed {value_max_length} characters") + def value_length(self) -> bool: + return self._value is None or len(self._value) <= self.value_max_length + + def to_dict(self) -> Dict[str, Any]: + self.validate_json() + json: Dict[str, Union[str, dict]] = {} + if self._text: + json["text"] = self._text.to_dict() + if self._accessibility_label: + json["accessibility_label"] = self._accessibility_label + if self._value: + json["value"] = self._value + return json + + class WorkflowTrigger(JsonObject): attributes = {"trigger"} diff --git a/slack_sdk/models/blocks/block_elements.py b/slack_sdk/models/blocks/block_elements.py index 4f0fc6d2d..f56e0d322 100644 --- a/slack_sdk/models/blocks/block_elements.py +++ b/slack_sdk/models/blocks/block_elements.py @@ -3,23 +3,24 @@ import re import warnings from abc import ABCMeta -from typing import Iterator, List, Optional, Set, Type, Union, Sequence, Dict, Any +from typing import Any, Dict, Iterator, List, Optional, Sequence, Set, Type, Union from slack_sdk.models import show_unknown_key_warning -from slack_sdk.models.basic_objects import ( - JsonObject, - JsonValidator, - EnumValidator, +from slack_sdk.models.basic_objects import EnumValidator, JsonObject, JsonValidator + +from .basic_components import ( + ButtonStyles, + ConfirmObject, + DispatchActionConfig, + FeedbackButtonObject, + MarkdownTextObject, + Option, + OptionGroup, + PlainTextObject, + SlackFile, + TextObject, + Workflow, ) -from .basic_components import ButtonStyles, Workflow, SlackFile -from .basic_components import ConfirmObject -from .basic_components import DispatchActionConfig -from .basic_components import MarkdownTextObject -from .basic_components import Option -from .basic_components import OptionGroup -from .basic_components import PlainTextObject -from .basic_components import TextObject - # ------------------------------------------------- # Block Elements @@ -539,6 +540,43 @@ def _validate_initial_date_time_valid(self) -> bool: return self.initial_date_time is None or (0 <= self.initial_date_time <= 9999999999) +# ------------------------------------------------- +# Feedback Buttons Element +# ------------------------------------------------- + + +class FeedbackButtonsElement(InteractiveElement): + type = "feedback_buttons" + + @property + def attributes(self) -> Set[str]: # type: ignore[override] + return super().attributes.union({"positive_button", "negative_button"}) + + def __init__( + self, + *, + action_id: Optional[str] = None, + positive_button: Union[dict, FeedbackButtonObject], + negative_button: Union[dict, FeedbackButtonObject], + **others: dict, + ): + """Buttons to indicate positive or negative feedback. + + Args: + action_id (required): An identifier for this action. + You can use this when you receive an interaction payload to identify the source of the action. + Should be unique among all other action_ids in the containing block. + Maximum length for this field is 255 characters. + positive_button (required): A button to indicate positive feedback. + negative_button (required): A button to indicate negative feedback. + """ + super().__init__(action_id=action_id, type=self.type) + show_unknown_key_warning(self, others) + + self.positive_button = FeedbackButtonObject.parse(positive_button) + self.negative_button = FeedbackButtonObject.parse(negative_button) + + # ------------------------------------------------- # Image # ------------------------------------------------- @@ -587,6 +625,59 @@ def _validate_alt_text_length(self) -> bool: return len(self.alt_text) <= self.alt_text_max_length # type: ignore[arg-type] +# ------------------------------------------------- +# Icon Button Element +# ------------------------------------------------- + + +class IconButtonElement(InteractiveElement): + type = "icon_button" + + @property + def attributes(self) -> Set[str]: # type: ignore[override] + return super().attributes.union({"icon", "text", "accessibility_label", "value", "visible_to_user_ids", "confirm"}) + + def __init__( + self, + *, + action_id: Optional[str] = None, + icon: str, + text: Union[str, dict, TextObject], + accessibility_label: Optional[str] = None, + value: Optional[str] = None, + visible_to_user_ids: Optional[List[str]] = None, + confirm: Optional[Union[dict, ConfirmObject]] = None, + **others: dict, + ): + """An icon button to perform actions. + + Args: + action_id: An identifier for this action. + You can use this when you receive an interaction payload to identify the source of the action. + Should be unique among all other action_ids in the containing block. + Maximum length for this field is 255 characters. + icon (required): The icon to show (e.g., 'trash'). + text (required): Defines an object containing some text. + accessibility_label: A label for longer descriptive text about a button element. + This label will be read out by screen readers instead of the button text object. + Maximum length for this field is 75 characters. + value: The button value. + Maximum length for this field is 2000 characters. + visible_to_user_ids: User IDs for which the icon appears. + Maximum length for this field is 10 user IDs. + confirm: A confirm object that defines an optional confirmation dialog after the button is clicked. + """ + super().__init__(action_id=action_id, type=self.type) + show_unknown_key_warning(self, others) + + self.icon = icon + self.text = TextObject.parse(text, PlainTextObject.type) + self.accessibility_label = accessibility_label + self.value = value + self.visible_to_user_ids = visible_to_user_ids + self.confirm = ConfirmObject.parse(confirm) if confirm else None + + # ------------------------------------------------- # Static Select # ------------------------------------------------- diff --git a/slack_sdk/models/blocks/blocks.py b/slack_sdk/models/blocks/blocks.py index 82a154056..569232dbe 100644 --- a/slack_sdk/models/blocks/blocks.py +++ b/slack_sdk/models/blocks/blocks.py @@ -4,19 +4,19 @@ from typing import Any, Dict, List, Optional, Sequence, Set, Union from slack_sdk.models import show_unknown_key_warning -from slack_sdk.models.basic_objects import ( - JsonObject, - JsonValidator, -) -from .basic_components import MarkdownTextObject, SlackFile -from .basic_components import PlainTextObject -from .basic_components import TextObject -from .block_elements import BlockElement, RichTextElement -from .block_elements import ImageElement -from .block_elements import InputInteractiveElement -from .block_elements import InteractiveElement -from ...errors import SlackObjectFormationError +from slack_sdk.models.basic_objects import JsonObject, JsonValidator +from ...errors import SlackObjectFormationError +from .basic_components import MarkdownTextObject, PlainTextObject, SlackFile, TextObject +from .block_elements import ( + BlockElement, + FeedbackButtonsElement, + IconButtonElement, + ImageElement, + InputInteractiveElement, + InteractiveElement, + RichTextElement, +) # ------------------------------------------------- # Base Classes @@ -79,6 +79,8 @@ def parse(cls, block: Union[dict, "Block"]) -> Optional["Block"]: return ActionsBlock(**block) elif type == ContextBlock.type: return ContextBlock(**block) + elif type == ContextActionsBlock.type: + return ContextActionsBlock(**block) elif type == InputBlock.type: return InputBlock(**block) elif type == FileBlock.type: @@ -357,6 +359,44 @@ def _validate_elements_length(self): return self.elements is None or len(self.elements) <= self.elements_max_length +class ContextActionsBlock(Block): + type = "context_actions" + elements_max_length = 5 + + @property + def attributes(self) -> Set[str]: # type: ignore[override] + return super().attributes.union({"elements"}) + + def __init__( + self, + *, + elements: Sequence[Union[dict, FeedbackButtonsElement, IconButtonElement]], + block_id: Optional[str] = None, + **others: dict, + ): + """Displays actions as contextual info, which can include both feedback buttons and icon buttons. + + Args: + elements (required): An array of feedback_buttons or icon_button block elements. Maximum number of items is 5. + block_id: A string acting as a unique identifier for a block. If not specified, one will be generated. + Maximum length for this field is 255 characters. + block_id should be unique for each message and each iteration of a message. + If a message is updated, use a new block_id. + """ + super().__init__(type=self.type, block_id=block_id) + show_unknown_key_warning(self, others) + + self.elements = BlockElement.parse_all(elements) + + @JsonValidator("elements attribute must be specified") + def _validate_elements(self): + return self.elements is None or len(self.elements) > 0 + + @JsonValidator(f"elements attribute cannot exceed {elements_max_length} elements") + def _validate_elements_length(self): + return self.elements is None or len(self.elements) <= self.elements_max_length + + class InputBlock(Block): type = "input" label_max_length = 2000 diff --git a/tests/slack_sdk/models/test_blocks.py b/tests/slack_sdk/models/test_blocks.py index f7d8c129b..561100cdd 100644 --- a/tests/slack_sdk/models/test_blocks.py +++ b/tests/slack_sdk/models/test_blocks.py @@ -4,33 +4,35 @@ from slack_sdk.errors import SlackObjectFormationError from slack_sdk.models.blocks import ( ActionsBlock, + Block, + ButtonElement, + CallBlock, + ContextActionsBlock, ContextBlock, DividerBlock, - ImageBlock, - SectionBlock, - InputBlock, FileBlock, - Block, - CallBlock, - ButtonElement, - StaticSelectElement, - OverflowMenuElement, + HeaderBlock, + ImageBlock, ImageElement, + InputBlock, LinkButtonElement, - PlainTextObject, - MarkdownTextObject, - HeaderBlock, MarkdownBlock, - VideoBlock, + MarkdownTextObject, Option, + OverflowMenuElement, + PlainTextObject, RichTextBlock, - RichTextSectionElement, + RichTextElementParts, RichTextListElement, - RichTextQuoteElement, RichTextPreformattedElement, - RichTextElementParts, + RichTextQuoteElement, + RichTextSectionElement, + SectionBlock, + StaticSelectElement, + VideoBlock, ) -from slack_sdk.models.blocks.basic_components import SlackFile +from slack_sdk.models.blocks.basic_components import FeedbackButtonObject, SlackFile +from slack_sdk.models.blocks.block_elements import FeedbackButtonsElement, IconButtonElement from . import STRING_3001_CHARS @@ -526,6 +528,54 @@ def test_element_parsing(self): self.assertDictEqual(original.to_dict(), parsed.to_dict()) +# ---------------------------------------------- +# ContextActionsBlock +# ---------------------------------------------- + + +class ContextActionsBlockTests(unittest.TestCase): + def test_document(self): + input = { + "type": "context_actions", + "block_id": "context-actions-1", + "elements": [ + { + "type": "feedback_buttons", + "action_id": "feedback-action", + "positive_button": {"text": {"type": "plain_text", "text": "+1"}, "value": "positive"}, + "negative_button": {"text": {"type": "plain_text", "text": "-1"}, "value": "negative"}, + }, + { + "type": "icon_button", + "action_id": "delete-action", + "icon": "trash", + "text": {"type": "plain_text", "text": "Delete"}, + "value": "delete", + }, + ], + } + self.assertDictEqual(input, ContextActionsBlock(**input).to_dict()) + self.assertDictEqual(input, Block.parse(input).to_dict()) + + def test_with_feedback_buttons(self): + feedback_buttons = FeedbackButtonsElement( + action_id="feedback-action", + positive_button=FeedbackButtonObject(text="Good", value="positive"), + negative_button=FeedbackButtonObject(text="Bad", value="negative"), + ) + block = ContextActionsBlock(elements=[feedback_buttons]) + self.assertEqual(len(block.elements), 1) + self.assertEqual(block.elements[0].type, "feedback_buttons") + + def test_with_icon_button(self): + icon_button = IconButtonElement( + action_id="icon-action", icon="star", text=PlainTextObject(text="Favorite"), value="favorite" + ) + block = ContextActionsBlock(elements=[icon_button]) + self.assertEqual(len(block.elements), 1) + self.assertEqual(block.elements[0].type, "icon_button") + + # ---------------------------------------------- # Context # ---------------------------------------------- diff --git a/tests/slack_sdk/models/test_elements.py b/tests/slack_sdk/models/test_elements.py index 6a9545b5e..421270266 100644 --- a/tests/slack_sdk/models/test_elements.py +++ b/tests/slack_sdk/models/test_elements.py @@ -4,44 +4,47 @@ from slack_sdk.models.blocks import ( BlockElement, ButtonElement, + ChannelMultiSelectElement, + ChannelSelectElement, + CheckboxesElement, + ConfirmObject, + ConversationMultiSelectElement, + ConversationSelectElement, DatePickerElement, - TimePickerElement, + ExternalDataMultiSelectElement, ExternalDataSelectElement, + FeedbackButtonsElement, + IconButtonElement, ImageElement, + InputInteractiveElement, + InteractiveElement, LinkButtonElement, - UserSelectElement, - StaticSelectElement, - CheckboxesElement, - StaticMultiSelectElement, - ExternalDataMultiSelectElement, - UserMultiSelectElement, - ConversationMultiSelectElement, - ChannelMultiSelectElement, + Option, OverflowMenuElement, PlainTextInputElement, - RadioButtonsElement, - ConversationSelectElement, - ChannelSelectElement, - ConfirmObject, - Option, - InputInteractiveElement, - InteractiveElement, PlainTextObject, + RadioButtonsElement, RichTextBlock, + StaticMultiSelectElement, + StaticSelectElement, + TimePickerElement, + UserMultiSelectElement, + UserSelectElement, ) from slack_sdk.models.blocks.basic_components import SlackFile from slack_sdk.models.blocks.block_elements import ( DateTimePickerElement, EmailInputElement, + FileInputElement, NumberInputElement, - UrlInputElement, - WorkflowButtonElement, + RichTextElementParts, RichTextInputElement, - FileInputElement, RichTextSectionElement, - RichTextElementParts, + UrlInputElement, + WorkflowButtonElement, ) -from . import STRING_3001_CHARS, STRING_301_CHARS + +from . import STRING_301_CHARS, STRING_3001_CHARS class BlockElementTests(unittest.TestCase): @@ -443,6 +446,67 @@ def test_focus_on_load(self): self.assertDictEqual(input, DateTimePickerElement(**input).to_dict()) +# ---------------------------------------------- +# FeedbackButtons +# ---------------------------------------------- + + +class FeedbackButtonsTests(unittest.TestCase): + def test_document(self): + input = { + "type": "feedback_buttons", + "action_id": "feedback-123", + "positive_button": { + "text": {"type": "plain_text", "text": "+1"}, + "accessibility_label": "Positive feedback", + "value": "positive", + }, + "negative_button": { + "text": {"type": "plain_text", "text": "-1"}, + "accessibility_label": "Negative feedback", + "value": "negative", + }, + } + self.assertDictEqual(input, FeedbackButtonsElement(**input).to_dict()) + + +# ---------------------------------------------- +# IconButton +# ---------------------------------------------- + + +class IconButtonTests(unittest.TestCase): + def test_document(self): + input = { + "type": "icon_button", + "action_id": "icon-123", + "icon": "trash", + "text": {"type": "plain_text", "text": "Delete"}, + "accessibility_label": "Delete item", + "value": "delete_item", + "visible_to_user_ids": ["U123456", "U789012"], + } + self.assertDictEqual(input, IconButtonElement(**input).to_dict()) + + def test_with_confirm(self): + input = { + "type": "icon_button", + "action_id": "icon-456", + "icon": "trash", + "text": {"type": "plain_text", "text": "Delete"}, + "value": "trash", + "confirm": { + "title": {"type": "plain_text", "text": "Are you sure?"}, + "text": {"type": "plain_text", "text": "This will send a warning."}, + "confirm": {"type": "plain_text", "text": "Yes"}, + "deny": {"type": "plain_text", "text": "No"}, + }, + } + icon_button = IconButtonElement(**input) + self.assertIsNotNone(icon_button.confirm) + self.assertDictEqual(input, icon_button.to_dict()) + + # ------------------------------------------------- # Image # ------------------------------------------------- diff --git a/tests/slack_sdk/models/test_objects.py b/tests/slack_sdk/models/test_objects.py index 383abee7c..30bcb7002 100644 --- a/tests/slack_sdk/models/test_objects.py +++ b/tests/slack_sdk/models/test_objects.py @@ -1,26 +1,14 @@ import copy import unittest -from typing import Optional, List, Union +from typing import List, Optional, Union from slack_sdk.errors import SlackObjectFormationError from slack_sdk.models import JsonObject, JsonValidator -from slack_sdk.models.blocks import ( - ConfirmObject, - MarkdownTextObject, - Option, - OptionGroup, - PlainTextObject, -) -from slack_sdk.models.blocks.basic_components import Workflow, WorkflowTrigger -from slack_sdk.models.messages import ( - ChannelLink, - DateLink, - EveryoneLink, - HereLink, - Link, - ObjectLink, -) -from . import STRING_301_CHARS, STRING_51_CHARS +from slack_sdk.models.blocks import ConfirmObject, MarkdownTextObject, Option, OptionGroup, PlainTextObject +from slack_sdk.models.blocks.basic_components import FeedbackButtonObject, Workflow, WorkflowTrigger +from slack_sdk.models.messages import ChannelLink, DateLink, EveryoneLink, HereLink, Link, ObjectLink + +from . import STRING_51_CHARS, STRING_301_CHARS class SimpleJsonObject(JsonObject): @@ -374,6 +362,58 @@ def test_deny_length(self): ConfirmObject(title="title", text="Are you sure?", deny=STRING_51_CHARS).to_dict() +class FeedbackButtonObjectTests(unittest.TestCase): + def test_basic_json(self): + feedback_button = FeedbackButtonObject(text="+1", value="positive") + expected = {"text": {"emoji": True, "text": "+1", "type": "plain_text"}, "value": "positive"} + self.assertDictEqual(expected, feedback_button.to_dict()) + + def test_with_accessibility_label(self): + feedback_button = FeedbackButtonObject(text="+1", value="positive", accessibility_label="Positive feedback button") + expected = { + "text": {"emoji": True, "text": "+1", "type": "plain_text"}, + "value": "positive", + "accessibility_label": "Positive feedback button", + } + self.assertDictEqual(expected, feedback_button.to_dict()) + + def test_with_plain_text_object(self): + text_obj = PlainTextObject(text="-1", emoji=False) + feedback_button = FeedbackButtonObject(text=text_obj, value="negative") + expected = { + "text": {"emoji": False, "text": "-1", "type": "plain_text"}, + "value": "negative", + } + self.assertDictEqual(expected, feedback_button.to_dict()) + + def test_text_length_validation(self): + with self.assertRaises(SlackObjectFormationError): + FeedbackButtonObject(text="a" * 76, value="test").to_dict() + + def test_value_length_validation(self): + with self.assertRaises(SlackObjectFormationError): + FeedbackButtonObject(text="+1", value="a" * 2001).to_dict() + + def test_parse_from_dict(self): + data = {"text": "+1", "value": "positive", "accessibility_label": "Positive feedback"} + parsed = FeedbackButtonObject.parse(data) + self.assertIsInstance(parsed, FeedbackButtonObject) + expected = { + "text": {"emoji": True, "text": "+1", "type": "plain_text"}, + "value": "positive", + "accessibility_label": "Positive feedback", + } + self.assertDictEqual(expected, parsed.to_dict()) + + def test_parse_from_existing_object(self): + original = FeedbackButtonObject(text="-1", value="negative") + parsed = FeedbackButtonObject.parse(original) + self.assertIs(original, parsed) + + def test_parse_none(self): + self.assertIsNone(FeedbackButtonObject.parse(None)) + + class OptionTests(unittest.TestCase): def setUp(self) -> None: self.common = Option(label="an option", value="option_1") From 12335dab3cf19b47c1ad1bffbc7843dfbc84235a Mon Sep 17 00:00:00 2001 From: Michael Brooks Date: Tue, 23 Sep 2025 19:41:11 -0700 Subject: [PATCH 07/21] feat(web-api): add recipient_team_id and recipient_user_id to chat_startStream method (#1751) --- docs/reference/index.html | 10 +++++++++- .../reference/oauth/installation_store/file/index.html | 2 +- docs/reference/oauth/installation_store/index.html | 2 +- docs/reference/oauth/state_store/file/index.html | 2 +- docs/reference/oauth/state_store/index.html | 2 +- docs/reference/web/async_client.html | 10 +++++++++- docs/reference/web/client.html | 10 +++++++++- docs/reference/web/index.html | 10 +++++++++- docs/reference/web/legacy_client.html | 10 +++++++++- slack_sdk/web/async_client.py | 4 ++++ slack_sdk/web/client.py | 4 ++++ slack_sdk/web/legacy_client.py | 4 ++++ tests/slack_sdk_async/web/test_web_client_coverage.py | 2 ++ 13 files changed, 63 insertions(+), 9 deletions(-) diff --git a/docs/reference/index.html b/docs/reference/index.html index b3d150db9..76ca5c1c4 100644 --- a/docs/reference/index.html +++ b/docs/reference/index.html @@ -3006,6 +3006,8 @@

      Classes

      channel: str, thread_ts: Optional[str] = None, markdown_text: Optional[str] = None, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, unfurl_links: Optional[bool] = None, unfurl_media: Optional[bool] = None, **kwargs, @@ -3018,6 +3020,8 @@

      Classes

      "channel": channel, "thread_ts": thread_ts, "markdown_text": markdown_text, + "recipient_team_id": recipient_team_id, + "recipient_user_id": recipient_user_id, "unfurl_links": unfurl_links, "unfurl_media": unfurl_media, } @@ -10264,7 +10268,7 @@

      Methods

      https://api.slack.com/methods/chat.scheduledMessages.list

      -def chat_startStream(self,
      *,
      channel: str,
      thread_ts: str | None = None,
      markdown_text: str | None = None,
      unfurl_links: bool | None = None,
      unfurl_media: bool | None = None,
      **kwargs) ‑> SlackResponse
      +def chat_startStream(self,
      *,
      channel: str,
      thread_ts: str | None = None,
      markdown_text: str | None = None,
      recipient_team_id: str | None = None,
      recipient_user_id: str | None = None,
      unfurl_links: bool | None = None,
      unfurl_media: bool | None = None,
      **kwargs) ‑> SlackResponse
      @@ -10277,6 +10281,8 @@

      Methods

      channel: str, thread_ts: Optional[str] = None, markdown_text: Optional[str] = None, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, unfurl_links: Optional[bool] = None, unfurl_media: Optional[bool] = None, **kwargs, @@ -10289,6 +10295,8 @@

      Methods

      "channel": channel, "thread_ts": thread_ts, "markdown_text": markdown_text, + "recipient_team_id": recipient_team_id, + "recipient_user_id": recipient_user_id, "unfurl_links": unfurl_links, "unfurl_media": unfurl_media, } diff --git a/docs/reference/oauth/installation_store/file/index.html b/docs/reference/oauth/installation_store/file/index.html index 7658ddd96..1091d3575 100644 --- a/docs/reference/oauth/installation_store/file/index.html +++ b/docs/reference/oauth/installation_store/file/index.html @@ -48,7 +48,7 @@

      Classes

      class FileInstallationStore -(*,
      base_dir: str = '/Users/eden.zimbelman/.bolt-app-installation',
      historical_data_enabled: bool = True,
      client_id: str | None = None,
      logger: logging.Logger = <Logger slack_sdk.oauth.installation_store.file (WARNING)>)
      +(*,
      base_dir: str = '/Users/michael.brooks/.bolt-app-installation',
      historical_data_enabled: bool = True,
      client_id: str | None = None,
      logger: logging.Logger = <Logger slack_sdk.oauth.installation_store.file (WARNING)>)
      diff --git a/docs/reference/oauth/installation_store/index.html b/docs/reference/oauth/installation_store/index.html index 5865522cf..aece243e9 100644 --- a/docs/reference/oauth/installation_store/index.html +++ b/docs/reference/oauth/installation_store/index.html @@ -327,7 +327,7 @@

      Methods

      class FileInstallationStore -(*,
      base_dir: str = '/Users/eden.zimbelman/.bolt-app-installation',
      historical_data_enabled: bool = True,
      client_id: str | None = None,
      logger: logging.Logger = <Logger slack_sdk.oauth.installation_store.file (WARNING)>)
      +(*,
      base_dir: str = '/Users/michael.brooks/.bolt-app-installation',
      historical_data_enabled: bool = True,
      client_id: str | None = None,
      logger: logging.Logger = <Logger slack_sdk.oauth.installation_store.file (WARNING)>)
      diff --git a/docs/reference/oauth/state_store/file/index.html b/docs/reference/oauth/state_store/file/index.html index 33ac16d82..d91be8db7 100644 --- a/docs/reference/oauth/state_store/file/index.html +++ b/docs/reference/oauth/state_store/file/index.html @@ -48,7 +48,7 @@

      Classes

      class FileOAuthStateStore -(*,
      expiration_seconds: int,
      base_dir: str = '/Users/eden.zimbelman/.bolt-app-oauth-state',
      client_id: str | None = None,
      logger: logging.Logger = <Logger slack_sdk.oauth.state_store.file (WARNING)>)
      +(*,
      expiration_seconds: int,
      base_dir: str = '/Users/michael.brooks/.bolt-app-oauth-state',
      client_id: str | None = None,
      logger: logging.Logger = <Logger slack_sdk.oauth.state_store.file (WARNING)>)
      diff --git a/docs/reference/oauth/state_store/index.html b/docs/reference/oauth/state_store/index.html index efb7d1cfe..a2f5a251e 100644 --- a/docs/reference/oauth/state_store/index.html +++ b/docs/reference/oauth/state_store/index.html @@ -77,7 +77,7 @@

      Classes

      class FileOAuthStateStore -(*,
      expiration_seconds: int,
      base_dir: str = '/Users/eden.zimbelman/.bolt-app-oauth-state',
      client_id: str | None = None,
      logger: logging.Logger = <Logger slack_sdk.oauth.state_store.file (WARNING)>)
      +(*,
      expiration_seconds: int,
      base_dir: str = '/Users/michael.brooks/.bolt-app-oauth-state',
      client_id: str | None = None,
      logger: logging.Logger = <Logger slack_sdk.oauth.state_store.file (WARNING)>)
      diff --git a/docs/reference/web/async_client.html b/docs/reference/web/async_client.html index 3ae302e59..e87f65501 100644 --- a/docs/reference/web/async_client.html +++ b/docs/reference/web/async_client.html @@ -2902,6 +2902,8 @@

      Classes

      channel: str, thread_ts: Optional[str] = None, markdown_text: Optional[str] = None, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, unfurl_links: Optional[bool] = None, unfurl_media: Optional[bool] = None, **kwargs, @@ -2914,6 +2916,8 @@

      Classes

      "channel": channel, "thread_ts": thread_ts, "markdown_text": markdown_text, + "recipient_team_id": recipient_team_id, + "recipient_user_id": recipient_user_id, "unfurl_links": unfurl_links, "unfurl_media": unfurl_media, } @@ -10160,7 +10164,7 @@

      Methods

      https://api.slack.com/methods/chat.scheduledMessages.list

      -async def chat_startStream(self,
      *,
      channel: str,
      thread_ts: str | None = None,
      markdown_text: str | None = None,
      unfurl_links: bool | None = None,
      unfurl_media: bool | None = None,
      **kwargs) ‑> AsyncSlackResponse
      +async def chat_startStream(self,
      *,
      channel: str,
      thread_ts: str | None = None,
      markdown_text: str | None = None,
      recipient_team_id: str | None = None,
      recipient_user_id: str | None = None,
      unfurl_links: bool | None = None,
      unfurl_media: bool | None = None,
      **kwargs) ‑> AsyncSlackResponse
      @@ -10173,6 +10177,8 @@

      Methods

      channel: str, thread_ts: Optional[str] = None, markdown_text: Optional[str] = None, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, unfurl_links: Optional[bool] = None, unfurl_media: Optional[bool] = None, **kwargs, @@ -10185,6 +10191,8 @@

      Methods

      "channel": channel, "thread_ts": thread_ts, "markdown_text": markdown_text, + "recipient_team_id": recipient_team_id, + "recipient_user_id": recipient_user_id, "unfurl_links": unfurl_links, "unfurl_media": unfurl_media, } diff --git a/docs/reference/web/client.html b/docs/reference/web/client.html index 12ddbb35d..a6c282b42 100644 --- a/docs/reference/web/client.html +++ b/docs/reference/web/client.html @@ -2902,6 +2902,8 @@

      Classes

      channel: str, thread_ts: Optional[str] = None, markdown_text: Optional[str] = None, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, unfurl_links: Optional[bool] = None, unfurl_media: Optional[bool] = None, **kwargs, @@ -2914,6 +2916,8 @@

      Classes

      "channel": channel, "thread_ts": thread_ts, "markdown_text": markdown_text, + "recipient_team_id": recipient_team_id, + "recipient_user_id": recipient_user_id, "unfurl_links": unfurl_links, "unfurl_media": unfurl_media, } @@ -10160,7 +10164,7 @@

      Methods

      https://api.slack.com/methods/chat.scheduledMessages.list

      -def chat_startStream(self,
      *,
      channel: str,
      thread_ts: str | None = None,
      markdown_text: str | None = None,
      unfurl_links: bool | None = None,
      unfurl_media: bool | None = None,
      **kwargs) ‑> SlackResponse
      +def chat_startStream(self,
      *,
      channel: str,
      thread_ts: str | None = None,
      markdown_text: str | None = None,
      recipient_team_id: str | None = None,
      recipient_user_id: str | None = None,
      unfurl_links: bool | None = None,
      unfurl_media: bool | None = None,
      **kwargs) ‑> SlackResponse
      @@ -10173,6 +10177,8 @@

      Methods

      channel: str, thread_ts: Optional[str] = None, markdown_text: Optional[str] = None, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, unfurl_links: Optional[bool] = None, unfurl_media: Optional[bool] = None, **kwargs, @@ -10185,6 +10191,8 @@

      Methods

      "channel": channel, "thread_ts": thread_ts, "markdown_text": markdown_text, + "recipient_team_id": recipient_team_id, + "recipient_user_id": recipient_user_id, "unfurl_links": unfurl_links, "unfurl_media": unfurl_media, } diff --git a/docs/reference/web/index.html b/docs/reference/web/index.html index bcee3c7ae..1e49e8dda 100644 --- a/docs/reference/web/index.html +++ b/docs/reference/web/index.html @@ -3263,6 +3263,8 @@

      Raises

      channel: str, thread_ts: Optional[str] = None, markdown_text: Optional[str] = None, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, unfurl_links: Optional[bool] = None, unfurl_media: Optional[bool] = None, **kwargs, @@ -3275,6 +3277,8 @@

      Raises

      "channel": channel, "thread_ts": thread_ts, "markdown_text": markdown_text, + "recipient_team_id": recipient_team_id, + "recipient_user_id": recipient_user_id, "unfurl_links": unfurl_links, "unfurl_media": unfurl_media, } @@ -10521,7 +10525,7 @@

      Methods

      https://api.slack.com/methods/chat.scheduledMessages.list

      -def chat_startStream(self,
      *,
      channel: str,
      thread_ts: str | None = None,
      markdown_text: str | None = None,
      unfurl_links: bool | None = None,
      unfurl_media: bool | None = None,
      **kwargs) ‑> SlackResponse
      +def chat_startStream(self,
      *,
      channel: str,
      thread_ts: str | None = None,
      markdown_text: str | None = None,
      recipient_team_id: str | None = None,
      recipient_user_id: str | None = None,
      unfurl_links: bool | None = None,
      unfurl_media: bool | None = None,
      **kwargs) ‑> SlackResponse
      @@ -10534,6 +10538,8 @@

      Methods

      channel: str, thread_ts: Optional[str] = None, markdown_text: Optional[str] = None, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, unfurl_links: Optional[bool] = None, unfurl_media: Optional[bool] = None, **kwargs, @@ -10546,6 +10552,8 @@

      Methods

      "channel": channel, "thread_ts": thread_ts, "markdown_text": markdown_text, + "recipient_team_id": recipient_team_id, + "recipient_user_id": recipient_user_id, "unfurl_links": unfurl_links, "unfurl_media": unfurl_media, } diff --git a/docs/reference/web/legacy_client.html b/docs/reference/web/legacy_client.html index 578ce8058..1cc442667 100644 --- a/docs/reference/web/legacy_client.html +++ b/docs/reference/web/legacy_client.html @@ -2901,6 +2901,8 @@

      Classes

      channel: str, thread_ts: Optional[str] = None, markdown_text: Optional[str] = None, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, unfurl_links: Optional[bool] = None, unfurl_media: Optional[bool] = None, **kwargs, @@ -2913,6 +2915,8 @@

      Classes

      "channel": channel, "thread_ts": thread_ts, "markdown_text": markdown_text, + "recipient_team_id": recipient_team_id, + "recipient_user_id": recipient_user_id, "unfurl_links": unfurl_links, "unfurl_media": unfurl_media, } @@ -10159,7 +10163,7 @@

      Methods

      https://api.slack.com/methods/chat.scheduledMessages.list

      -def chat_startStream(self,
      *,
      channel: str,
      thread_ts: str | None = None,
      markdown_text: str | None = None,
      unfurl_links: bool | None = None,
      unfurl_media: bool | None = None,
      **kwargs) ‑> _asyncio.Future | LegacySlackResponse
      +def chat_startStream(self,
      *,
      channel: str,
      thread_ts: str | None = None,
      markdown_text: str | None = None,
      recipient_team_id: str | None = None,
      recipient_user_id: str | None = None,
      unfurl_links: bool | None = None,
      unfurl_media: bool | None = None,
      **kwargs) ‑> _asyncio.Future | LegacySlackResponse
      @@ -10172,6 +10176,8 @@

      Methods

      channel: str, thread_ts: Optional[str] = None, markdown_text: Optional[str] = None, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, unfurl_links: Optional[bool] = None, unfurl_media: Optional[bool] = None, **kwargs, @@ -10184,6 +10190,8 @@

      Methods

      "channel": channel, "thread_ts": thread_ts, "markdown_text": markdown_text, + "recipient_team_id": recipient_team_id, + "recipient_user_id": recipient_user_id, "unfurl_links": unfurl_links, "unfurl_media": unfurl_media, } diff --git a/slack_sdk/web/async_client.py b/slack_sdk/web/async_client.py index 3894cbfa3..84a490920 100644 --- a/slack_sdk/web/async_client.py +++ b/slack_sdk/web/async_client.py @@ -2880,6 +2880,8 @@ async def chat_startStream( channel: str, thread_ts: Optional[str] = None, markdown_text: Optional[str] = None, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, unfurl_links: Optional[bool] = None, unfurl_media: Optional[bool] = None, **kwargs, @@ -2892,6 +2894,8 @@ async def chat_startStream( "channel": channel, "thread_ts": thread_ts, "markdown_text": markdown_text, + "recipient_team_id": recipient_team_id, + "recipient_user_id": recipient_user_id, "unfurl_links": unfurl_links, "unfurl_media": unfurl_media, } diff --git a/slack_sdk/web/client.py b/slack_sdk/web/client.py index 3314e336d..cdce5f975 100644 --- a/slack_sdk/web/client.py +++ b/slack_sdk/web/client.py @@ -2870,6 +2870,8 @@ def chat_startStream( channel: str, thread_ts: Optional[str] = None, markdown_text: Optional[str] = None, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, unfurl_links: Optional[bool] = None, unfurl_media: Optional[bool] = None, **kwargs, @@ -2882,6 +2884,8 @@ def chat_startStream( "channel": channel, "thread_ts": thread_ts, "markdown_text": markdown_text, + "recipient_team_id": recipient_team_id, + "recipient_user_id": recipient_user_id, "unfurl_links": unfurl_links, "unfurl_media": unfurl_media, } diff --git a/slack_sdk/web/legacy_client.py b/slack_sdk/web/legacy_client.py index 385f1839a..10d2c7afb 100644 --- a/slack_sdk/web/legacy_client.py +++ b/slack_sdk/web/legacy_client.py @@ -2882,6 +2882,8 @@ def chat_startStream( channel: str, thread_ts: Optional[str] = None, markdown_text: Optional[str] = None, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, unfurl_links: Optional[bool] = None, unfurl_media: Optional[bool] = None, **kwargs, @@ -2894,6 +2896,8 @@ def chat_startStream( "channel": channel, "thread_ts": thread_ts, "markdown_text": markdown_text, + "recipient_team_id": recipient_team_id, + "recipient_user_id": recipient_user_id, "unfurl_links": unfurl_links, "unfurl_media": unfurl_media, } diff --git a/tests/slack_sdk_async/web/test_web_client_coverage.py b/tests/slack_sdk_async/web/test_web_client_coverage.py index a335f5ded..d7451dd7d 100644 --- a/tests/slack_sdk_async/web/test_web_client_coverage.py +++ b/tests/slack_sdk_async/web/test_web_client_coverage.py @@ -569,7 +569,9 @@ async def run_method(self, method_name, method, async_method): await async_method() elif method_name == "chat_startStream": self.api_methods_to_call.remove(method(channel="C123")["method"]) + method(channel="C123", recipient_team_id="T123", recipient_user_id="U123") await async_method(channel="C123") + await async_method(channel="C123", recipient_team_id="T123", recipient_user_id="U123") elif method_name == "chat_stopStream": self.api_methods_to_call.remove( method(channel="C123", ts="123.123", blocks=[{"type": "markdown", "text": "**twelve**"}])["method"] From 01d331b8c953b08d23ad9c4fbb8343d1bcdc8202 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 23 Sep 2025 21:33:22 -0700 Subject: [PATCH 08/21] chore(release): version 3.36.0.dev2 --- docs/reference/models/basic_objects.html | 1 + .../models/blocks/basic_components.html | 162 ++++++ .../models/blocks/block_elements.html | 208 ++++++++ docs/reference/models/blocks/blocks.html | 116 +++++ docs/reference/models/blocks/index.html | 486 ++++++++++++++++++ docs/reference/models/index.html | 1 + .../oauth/installation_store/file/index.html | 2 +- .../oauth/installation_store/index.html | 2 +- .../oauth/state_store/file/index.html | 2 +- docs/reference/oauth/state_store/index.html | 2 +- slack_sdk/version.py | 2 +- 11 files changed, 979 insertions(+), 5 deletions(-) diff --git a/docs/reference/models/basic_objects.html b/docs/reference/models/basic_objects.html index b49694566..972273cc9 100644 --- a/docs/reference/models/basic_objects.html +++ b/docs/reference/models/basic_objects.html @@ -194,6 +194,7 @@

      Subclasses

    • AttachmentField
    • ConfirmObject
    • DispatchActionConfig
    • +
    • FeedbackButtonObject
    • Option
    • OptionGroup
    • SlackFile
    • diff --git a/docs/reference/models/blocks/basic_components.html b/docs/reference/models/blocks/basic_components.html index 7b56352d3..2a827b01a 100644 --- a/docs/reference/models/blocks/basic_components.html +++ b/docs/reference/models/blocks/basic_components.html @@ -341,6 +341,157 @@

      Inherited members

    +
    +class FeedbackButtonObject +(*,
    text: str | Dict[str, Any] | PlainTextObject,
    accessibility_label: str | None = None,
    value: str,
    **others: Dict[str, Any])
    +
    +
    +
    + +Expand source code + +
    class FeedbackButtonObject(JsonObject):
    +    attributes: Set[str] = set()
    +
    +    text_max_length = 75
    +    value_max_length = 2000
    +
    +    @classmethod
    +    def parse(cls, feedback_button: Union["FeedbackButtonObject", Dict[str, Any]]):
    +        if feedback_button:
    +            if isinstance(feedback_button, FeedbackButtonObject):
    +                return feedback_button
    +            elif isinstance(feedback_button, dict):
    +                return FeedbackButtonObject(**feedback_button)
    +            else:
    +                # Not yet implemented: show some warning here
    +                return None
    +        return None
    +
    +    def __init__(
    +        self,
    +        *,
    +        text: Union[str, Dict[str, Any], PlainTextObject],
    +        accessibility_label: Optional[str] = None,
    +        value: str,
    +        **others: Dict[str, Any],
    +    ):
    +        """
    +        A feedback button element object for either positive or negative feedback.
    +
    +        Args:
    +            text (required): An object containing some text. Maximum length for this field is 75 characters.
    +            accessibility_label: A label for longer descriptive text about a button element. This label will be read out by
    +                screen readers instead of the button `text` object.
    +            value (required): The button value. Maximum length for this field is 2000 characters.
    +        """
    +        self._text: Optional[TextObject] = PlainTextObject.parse(text, default_type=PlainTextObject.type)
    +        self._accessibility_label: Optional[str] = accessibility_label
    +        self._value: Optional[str] = value
    +        show_unknown_key_warning(self, others)
    +
    +    @JsonValidator(f"text attribute cannot exceed {text_max_length} characters")
    +    def text_length(self) -> bool:
    +        return self._text is None or len(self._text.text) <= self.text_max_length
    +
    +    @JsonValidator(f"value attribute cannot exceed {value_max_length} characters")
    +    def value_length(self) -> bool:
    +        return self._value is None or len(self._value) <= self.value_max_length
    +
    +    def to_dict(self) -> Dict[str, Any]:
    +        self.validate_json()
    +        json: Dict[str, Union[str, dict]] = {}
    +        if self._text:
    +            json["text"] = self._text.to_dict()
    +        if self._accessibility_label:
    +            json["accessibility_label"] = self._accessibility_label
    +        if self._value:
    +            json["value"] = self._value
    +        return json
    +
    +

    The base class for JSON serializable class objects

    +

    A feedback button element object for either positive or negative feedback.

    +

    Args

    +
    +
    text : required
    +
    An object containing some text. Maximum length for this field is 75 characters.
    +
    accessibility_label
    +
    A label for longer descriptive text about a button element. This label will be read out by +screen readers instead of the button text object.
    +
    value : required
    +
    The button value. Maximum length for this field is 2000 characters.
    +
    +

    Ancestors

    + +

    Class variables

    +
    +
    var attributes : Set[str]
    +
    +

    The type of the None singleton.

    +
    +
    var text_max_length
    +
    +

    The type of the None singleton.

    +
    +
    var value_max_length
    +
    +

    The type of the None singleton.

    +
    +
    +

    Static methods

    +
    +
    +def parse(feedback_button: ForwardRef('FeedbackButtonObject') | Dict[str, Any]) +
    +
    +
    +
    +
    +

    Methods

    +
    +
    +def text_length(self) ‑> bool +
    +
    +
    + +Expand source code + +
    @JsonValidator(f"text attribute cannot exceed {text_max_length} characters")
    +def text_length(self) -> bool:
    +    return self._text is None or len(self._text.text) <= self.text_max_length
    +
    +
    +
    +
    +def value_length(self) ‑> bool +
    +
    +
    + +Expand source code + +
    @JsonValidator(f"value attribute cannot exceed {value_max_length} characters")
    +def value_length(self) -> bool:
    +    return self._value is None or len(self._value) <= self.value_max_length
    +
    +
    +
    +
    +

    Inherited members

    + +
    class MarkdownTextObject (*, text: str, verbatim: bool | None = None) @@ -1427,6 +1578,17 @@

    FeedbackButtonObject

    + +
  • +
  • MarkdownTextObject

    • attributes
    • diff --git a/docs/reference/models/blocks/block_elements.html b/docs/reference/models/blocks/block_elements.html index 1bdb0fb82..a7391d7c0 100644 --- a/docs/reference/models/blocks/block_elements.html +++ b/docs/reference/models/blocks/block_elements.html @@ -1843,6 +1843,89 @@

      Inherited members

    +
    +class FeedbackButtonsElement +(*,
    action_id: str | None = None,
    positive_button: dict | FeedbackButtonObject,
    negative_button: dict | FeedbackButtonObject,
    **others: dict)
    +
    +
    +
    + +Expand source code + +
    class FeedbackButtonsElement(InteractiveElement):
    +    type = "feedback_buttons"
    +
    +    @property
    +    def attributes(self) -> Set[str]:  # type: ignore[override]
    +        return super().attributes.union({"positive_button", "negative_button"})
    +
    +    def __init__(
    +        self,
    +        *,
    +        action_id: Optional[str] = None,
    +        positive_button: Union[dict, FeedbackButtonObject],
    +        negative_button: Union[dict, FeedbackButtonObject],
    +        **others: dict,
    +    ):
    +        """Buttons to indicate positive or negative feedback.
    +
    +        Args:
    +            action_id (required): An identifier for this action.
    +                You can use this when you receive an interaction payload to identify the source of the action.
    +                Should be unique among all other action_ids in the containing block.
    +                Maximum length for this field is 255 characters.
    +            positive_button (required): A button to indicate positive feedback.
    +            negative_button (required): A button to indicate negative feedback.
    +        """
    +        super().__init__(action_id=action_id, type=self.type)
    +        show_unknown_key_warning(self, others)
    +
    +        self.positive_button = FeedbackButtonObject.parse(positive_button)
    +        self.negative_button = FeedbackButtonObject.parse(negative_button)
    +
    +

    Block Elements are things that exists inside of your Blocks. +https://api.slack.com/reference/block-kit/block-elements

    +

    Buttons to indicate positive or negative feedback.

    +

    Args

    +
    +
    action_id : required
    +
    An identifier for this action. +You can use this when you receive an interaction payload to identify the source of the action. +Should be unique among all other action_ids in the containing block. +Maximum length for this field is 255 characters.
    +
    positive_button : required
    +
    A button to indicate positive feedback.
    +
    negative_button : required
    +
    A button to indicate negative feedback.
    +
    +

    Ancestors

    + +

    Class variables

    +
    +
    var type
    +
    +

    The type of the None singleton.

    +
    +
    +

    Inherited members

    + +
    class FileInputElement (*,
    action_id: str | None = None,
    filetypes: List[str] | None = None,
    max_files: int | None = None,
    **others: dict)
    @@ -1962,6 +2045,117 @@

    Inherited members

  • +
    +class IconButtonElement +(*,
    action_id: str | None = None,
    icon: str,
    text: str | dict | TextObject,
    accessibility_label: str | None = None,
    value: str | None = None,
    visible_to_user_ids: List[str] | None = None,
    confirm: dict | ConfirmObject | None = None,
    **others: dict)
    +
    +
    +
    + +Expand source code + +
    class IconButtonElement(InteractiveElement):
    +    type = "icon_button"
    +
    +    @property
    +    def attributes(self) -> Set[str]:  # type: ignore[override]
    +        return super().attributes.union({"icon", "text", "accessibility_label", "value", "visible_to_user_ids", "confirm"})
    +
    +    def __init__(
    +        self,
    +        *,
    +        action_id: Optional[str] = None,
    +        icon: str,
    +        text: Union[str, dict, TextObject],
    +        accessibility_label: Optional[str] = None,
    +        value: Optional[str] = None,
    +        visible_to_user_ids: Optional[List[str]] = None,
    +        confirm: Optional[Union[dict, ConfirmObject]] = None,
    +        **others: dict,
    +    ):
    +        """An icon button to perform actions.
    +
    +        Args:
    +            action_id: An identifier for this action.
    +                You can use this when you receive an interaction payload to identify the source of the action.
    +                Should be unique among all other action_ids in the containing block.
    +                Maximum length for this field is 255 characters.
    +            icon (required): The icon to show (e.g., 'trash').
    +            text (required): Defines an object containing some text.
    +            accessibility_label: A label for longer descriptive text about a button element.
    +                This label will be read out by screen readers instead of the button text object.
    +                Maximum length for this field is 75 characters.
    +            value: The button value.
    +                Maximum length for this field is 2000 characters.
    +            visible_to_user_ids: User IDs for which the icon appears.
    +                Maximum length for this field is 10 user IDs.
    +            confirm: A confirm object that defines an optional confirmation dialog after the button is clicked.
    +        """
    +        super().__init__(action_id=action_id, type=self.type)
    +        show_unknown_key_warning(self, others)
    +
    +        self.icon = icon
    +        self.text = TextObject.parse(text, PlainTextObject.type)
    +        self.accessibility_label = accessibility_label
    +        self.value = value
    +        self.visible_to_user_ids = visible_to_user_ids
    +        self.confirm = ConfirmObject.parse(confirm) if confirm else None
    +
    +

    Block Elements are things that exists inside of your Blocks. +https://api.slack.com/reference/block-kit/block-elements

    +

    An icon button to perform actions.

    +

    Args

    +
    +
    action_id
    +
    An identifier for this action. +You can use this when you receive an interaction payload to identify the source of the action. +Should be unique among all other action_ids in the containing block. +Maximum length for this field is 255 characters.
    +
    icon : required
    +
    The icon to show (e.g., 'trash').
    +
    text : required
    +
    Defines an object containing some text.
    +
    accessibility_label
    +
    A label for longer descriptive text about a button element. +This label will be read out by screen readers instead of the button text object. +Maximum length for this field is 75 characters.
    +
    value
    +
    The button value. +Maximum length for this field is 2000 characters.
    +
    visible_to_user_ids
    +
    User IDs for which the icon appears. +Maximum length for this field is 10 user IDs.
    +
    confirm
    +
    A confirm object that defines an optional confirmation dialog after the button is clicked.
    +
    +

    Ancestors

    + +

    Class variables

    +
    +
    var type
    +
    +

    The type of the None singleton.

    +
    +
    +

    Inherited members

    + +
    class ImageElement (*,
    alt_text: str | None = None,
    image_url: str | None = None,
    slack_file: Dict[str, Any] | SlackFile | None = None,
    **others: dict)
    @@ -2259,6 +2453,8 @@

    Ancestors

    Subclasses

    • ButtonElement
    • +
    • FeedbackButtonsElement
    • +
    • IconButtonElement
    • InputInteractiveElement
    • OverflowMenuElement
    • WorkflowButtonElement
    • @@ -4946,6 +5142,12 @@

      FeedbackButtonsElement

      + + +
    • FileInputElement

      • attributes
      • @@ -4953,6 +5155,12 @@

      • +

        IconButtonElement

        + +
      • +
      • ImageElement

        • alt_text_max_length
        • diff --git a/docs/reference/models/blocks/blocks.html b/docs/reference/models/blocks/blocks.html index efb2e41ab..92d9e9cc8 100644 --- a/docs/reference/models/blocks/blocks.html +++ b/docs/reference/models/blocks/blocks.html @@ -220,6 +220,8 @@

          Inherited members

          return ActionsBlock(**block) elif type == ContextBlock.type: return ContextBlock(**block) + elif type == ContextActionsBlock.type: + return ContextActionsBlock(**block) elif type == InputBlock.type: return InputBlock(**block) elif type == FileBlock.type: @@ -257,6 +259,7 @@

          Subclasses

          +
          +class ContextActionsBlock +(*,
          elements: Sequence[dict | FeedbackButtonsElement | IconButtonElement],
          block_id: str | None = None,
          **others: dict)
          +
          +
          +
          + +Expand source code + +
          class ContextActionsBlock(Block):
          +    type = "context_actions"
          +    elements_max_length = 5
          +
          +    @property
          +    def attributes(self) -> Set[str]:  # type: ignore[override]
          +        return super().attributes.union({"elements"})
          +
          +    def __init__(
          +        self,
          +        *,
          +        elements: Sequence[Union[dict, FeedbackButtonsElement, IconButtonElement]],
          +        block_id: Optional[str] = None,
          +        **others: dict,
          +    ):
          +        """Displays actions as contextual info, which can include both feedback buttons and icon buttons.
          +
          +        Args:
          +            elements (required): An array of feedback_buttons or icon_button block elements. Maximum number of items is 5.
          +            block_id: A string acting as a unique identifier for a block. If not specified, one will be generated.
          +                Maximum length for this field is 255 characters.
          +                block_id should be unique for each message and each iteration of a message.
          +                If a message is updated, use a new block_id.
          +        """
          +        super().__init__(type=self.type, block_id=block_id)
          +        show_unknown_key_warning(self, others)
          +
          +        self.elements = BlockElement.parse_all(elements)
          +
          +    @JsonValidator("elements attribute must be specified")
          +    def _validate_elements(self):
          +        return self.elements is None or len(self.elements) > 0
          +
          +    @JsonValidator(f"elements attribute cannot exceed {elements_max_length} elements")
          +    def _validate_elements_length(self):
          +        return self.elements is None or len(self.elements) <= self.elements_max_length
          +
          +

          Blocks are a series of components that can be combined +to create visually rich and compellingly interactive messages. +https://api.slack.com/reference/block-kit/blocks

          +

          Displays actions as contextual info, which can include both feedback buttons and icon buttons.

          +

          Args

          +
          +
          elements : required
          +
          An array of feedback_buttons or icon_button block elements. Maximum number of items is 5.
          +
          block_id
          +
          A string acting as a unique identifier for a block. If not specified, one will be generated. +Maximum length for this field is 255 characters. +block_id should be unique for each message and each iteration of a message. +If a message is updated, use a new block_id.
          +
          +

          Ancestors

          + +

          Class variables

          +
          +
          var elements_max_length
          +
          +

          The type of the None singleton.

          +
          +
          var type
          +
          +

          The type of the None singleton.

          +
          +
          +

          Instance variables

          +
          +
          prop attributes : Set[str]
          +
          +
          + +Expand source code + +
          @property
          +def attributes(self) -> Set[str]:  # type: ignore[override]
          +    return super().attributes.union({"elements"})
          +
          +

          Build an unordered collection of unique elements.

          +
          +
          +

          Inherited members

          + +
          class ContextBlock (*,
          elements: Sequence[dict | ImageElement | TextObject],
          block_id: str | None = None,
          **others: dict)
          @@ -1714,6 +1822,14 @@

          ContextActionsBlock

          + + +
        • ContextBlock

          • attributes
          • diff --git a/docs/reference/models/blocks/index.html b/docs/reference/models/blocks/index.html index 7a69ec6e6..5d049c328 100644 --- a/docs/reference/models/blocks/index.html +++ b/docs/reference/models/blocks/index.html @@ -242,6 +242,8 @@

            Inherited members

            return ActionsBlock(**block) elif type == ContextBlock.type: return ContextBlock(**block) + elif type == ContextActionsBlock.type: + return ContextActionsBlock(**block) elif type == InputBlock.type: return InputBlock(**block) elif type == FileBlock.type: @@ -279,6 +281,7 @@

            Subclasses

            +
            +class ContextActionsBlock +(*,
            elements: Sequence[dict | FeedbackButtonsElement | IconButtonElement],
            block_id: str | None = None,
            **others: dict)
            +
            +
            +
            + +Expand source code + +
            class ContextActionsBlock(Block):
            +    type = "context_actions"
            +    elements_max_length = 5
            +
            +    @property
            +    def attributes(self) -> Set[str]:  # type: ignore[override]
            +        return super().attributes.union({"elements"})
            +
            +    def __init__(
            +        self,
            +        *,
            +        elements: Sequence[Union[dict, FeedbackButtonsElement, IconButtonElement]],
            +        block_id: Optional[str] = None,
            +        **others: dict,
            +    ):
            +        """Displays actions as contextual info, which can include both feedback buttons and icon buttons.
            +
            +        Args:
            +            elements (required): An array of feedback_buttons or icon_button block elements. Maximum number of items is 5.
            +            block_id: A string acting as a unique identifier for a block. If not specified, one will be generated.
            +                Maximum length for this field is 255 characters.
            +                block_id should be unique for each message and each iteration of a message.
            +                If a message is updated, use a new block_id.
            +        """
            +        super().__init__(type=self.type, block_id=block_id)
            +        show_unknown_key_warning(self, others)
            +
            +        self.elements = BlockElement.parse_all(elements)
            +
            +    @JsonValidator("elements attribute must be specified")
            +    def _validate_elements(self):
            +        return self.elements is None or len(self.elements) > 0
            +
            +    @JsonValidator(f"elements attribute cannot exceed {elements_max_length} elements")
            +    def _validate_elements_length(self):
            +        return self.elements is None or len(self.elements) <= self.elements_max_length
            +
            +

            Blocks are a series of components that can be combined +to create visually rich and compellingly interactive messages. +https://api.slack.com/reference/block-kit/blocks

            +

            Displays actions as contextual info, which can include both feedback buttons and icon buttons.

            +

            Args

            +
            +
            elements : required
            +
            An array of feedback_buttons or icon_button block elements. Maximum number of items is 5.
            +
            block_id
            +
            A string acting as a unique identifier for a block. If not specified, one will be generated. +Maximum length for this field is 255 characters. +block_id should be unique for each message and each iteration of a message. +If a message is updated, use a new block_id.
            +
            +

            Ancestors

            + +

            Class variables

            +
            +
            var elements_max_length
            +
            +

            The type of the None singleton.

            +
            +
            var type
            +
            +

            The type of the None singleton.

            +
            +
            +

            Instance variables

            +
            +
            prop attributes : Set[str]
            +
            +
            + +Expand source code + +
            @property
            +def attributes(self) -> Set[str]:  # type: ignore[override]
            +    return super().attributes.union({"elements"})
            +
            +

            Build an unordered collection of unique elements.

            +
            +
            +

            Inherited members

            + +
            class ContextBlock (*,
            elements: Sequence[dict | ImageElement | TextObject],
            block_id: str | None = None,
            **others: dict)
            @@ -2617,6 +2725,240 @@

            Inherited members

          +
          +class FeedbackButtonObject +(*,
          text: str | Dict[str, Any] | PlainTextObject,
          accessibility_label: str | None = None,
          value: str,
          **others: Dict[str, Any])
          +
          +
          +
          + +Expand source code + +
          class FeedbackButtonObject(JsonObject):
          +    attributes: Set[str] = set()
          +
          +    text_max_length = 75
          +    value_max_length = 2000
          +
          +    @classmethod
          +    def parse(cls, feedback_button: Union["FeedbackButtonObject", Dict[str, Any]]):
          +        if feedback_button:
          +            if isinstance(feedback_button, FeedbackButtonObject):
          +                return feedback_button
          +            elif isinstance(feedback_button, dict):
          +                return FeedbackButtonObject(**feedback_button)
          +            else:
          +                # Not yet implemented: show some warning here
          +                return None
          +        return None
          +
          +    def __init__(
          +        self,
          +        *,
          +        text: Union[str, Dict[str, Any], PlainTextObject],
          +        accessibility_label: Optional[str] = None,
          +        value: str,
          +        **others: Dict[str, Any],
          +    ):
          +        """
          +        A feedback button element object for either positive or negative feedback.
          +
          +        Args:
          +            text (required): An object containing some text. Maximum length for this field is 75 characters.
          +            accessibility_label: A label for longer descriptive text about a button element. This label will be read out by
          +                screen readers instead of the button `text` object.
          +            value (required): The button value. Maximum length for this field is 2000 characters.
          +        """
          +        self._text: Optional[TextObject] = PlainTextObject.parse(text, default_type=PlainTextObject.type)
          +        self._accessibility_label: Optional[str] = accessibility_label
          +        self._value: Optional[str] = value
          +        show_unknown_key_warning(self, others)
          +
          +    @JsonValidator(f"text attribute cannot exceed {text_max_length} characters")
          +    def text_length(self) -> bool:
          +        return self._text is None or len(self._text.text) <= self.text_max_length
          +
          +    @JsonValidator(f"value attribute cannot exceed {value_max_length} characters")
          +    def value_length(self) -> bool:
          +        return self._value is None or len(self._value) <= self.value_max_length
          +
          +    def to_dict(self) -> Dict[str, Any]:
          +        self.validate_json()
          +        json: Dict[str, Union[str, dict]] = {}
          +        if self._text:
          +            json["text"] = self._text.to_dict()
          +        if self._accessibility_label:
          +            json["accessibility_label"] = self._accessibility_label
          +        if self._value:
          +            json["value"] = self._value
          +        return json
          +
          +

          The base class for JSON serializable class objects

          +

          A feedback button element object for either positive or negative feedback.

          +

          Args

          +
          +
          text : required
          +
          An object containing some text. Maximum length for this field is 75 characters.
          +
          accessibility_label
          +
          A label for longer descriptive text about a button element. This label will be read out by +screen readers instead of the button text object.
          +
          value : required
          +
          The button value. Maximum length for this field is 2000 characters.
          +
          +

          Ancestors

          + +

          Class variables

          +
          +
          var attributes : Set[str]
          +
          +

          The type of the None singleton.

          +
          +
          var text_max_length
          +
          +

          The type of the None singleton.

          +
          +
          var value_max_length
          +
          +

          The type of the None singleton.

          +
          +
          +

          Static methods

          +
          +
          +def parse(feedback_button: ForwardRef('FeedbackButtonObject') | Dict[str, Any]) +
          +
          +
          +
          +
          +

          Methods

          +
          +
          +def text_length(self) ‑> bool +
          +
          +
          + +Expand source code + +
          @JsonValidator(f"text attribute cannot exceed {text_max_length} characters")
          +def text_length(self) -> bool:
          +    return self._text is None or len(self._text.text) <= self.text_max_length
          +
          +
          +
          +
          +def value_length(self) ‑> bool +
          +
          +
          + +Expand source code + +
          @JsonValidator(f"value attribute cannot exceed {value_max_length} characters")
          +def value_length(self) -> bool:
          +    return self._value is None or len(self._value) <= self.value_max_length
          +
          +
          +
          +
          +

          Inherited members

          + +
          +
          +class FeedbackButtonsElement +(*,
          action_id: str | None = None,
          positive_button: dict | FeedbackButtonObject,
          negative_button: dict | FeedbackButtonObject,
          **others: dict)
          +
          +
          +
          + +Expand source code + +
          class FeedbackButtonsElement(InteractiveElement):
          +    type = "feedback_buttons"
          +
          +    @property
          +    def attributes(self) -> Set[str]:  # type: ignore[override]
          +        return super().attributes.union({"positive_button", "negative_button"})
          +
          +    def __init__(
          +        self,
          +        *,
          +        action_id: Optional[str] = None,
          +        positive_button: Union[dict, FeedbackButtonObject],
          +        negative_button: Union[dict, FeedbackButtonObject],
          +        **others: dict,
          +    ):
          +        """Buttons to indicate positive or negative feedback.
          +
          +        Args:
          +            action_id (required): An identifier for this action.
          +                You can use this when you receive an interaction payload to identify the source of the action.
          +                Should be unique among all other action_ids in the containing block.
          +                Maximum length for this field is 255 characters.
          +            positive_button (required): A button to indicate positive feedback.
          +            negative_button (required): A button to indicate negative feedback.
          +        """
          +        super().__init__(action_id=action_id, type=self.type)
          +        show_unknown_key_warning(self, others)
          +
          +        self.positive_button = FeedbackButtonObject.parse(positive_button)
          +        self.negative_button = FeedbackButtonObject.parse(negative_button)
          +
          +

          Block Elements are things that exists inside of your Blocks. +https://api.slack.com/reference/block-kit/block-elements

          +

          Buttons to indicate positive or negative feedback.

          +

          Args

          +
          +
          action_id : required
          +
          An identifier for this action. +You can use this when you receive an interaction payload to identify the source of the action. +Should be unique among all other action_ids in the containing block. +Maximum length for this field is 255 characters.
          +
          positive_button : required
          +
          A button to indicate positive feedback.
          +
          negative_button : required
          +
          A button to indicate negative feedback.
          +
          +

          Ancestors

          + +

          Class variables

          +
          +
          var type
          +
          +

          The type of the None singleton.

          +
          +
          +

          Inherited members

          + +
          class FileBlock (*,
          external_id: str,
          source: str = 'remote',
          block_id: str | None = None,
          **others: dict)
          @@ -2825,6 +3167,117 @@

          Inherited members

        +
        +class IconButtonElement +(*,
        action_id: str | None = None,
        icon: str,
        text: str | dict | TextObject,
        accessibility_label: str | None = None,
        value: str | None = None,
        visible_to_user_ids: List[str] | None = None,
        confirm: dict | ConfirmObject | None = None,
        **others: dict)
        +
        +
        +
        + +Expand source code + +
        class IconButtonElement(InteractiveElement):
        +    type = "icon_button"
        +
        +    @property
        +    def attributes(self) -> Set[str]:  # type: ignore[override]
        +        return super().attributes.union({"icon", "text", "accessibility_label", "value", "visible_to_user_ids", "confirm"})
        +
        +    def __init__(
        +        self,
        +        *,
        +        action_id: Optional[str] = None,
        +        icon: str,
        +        text: Union[str, dict, TextObject],
        +        accessibility_label: Optional[str] = None,
        +        value: Optional[str] = None,
        +        visible_to_user_ids: Optional[List[str]] = None,
        +        confirm: Optional[Union[dict, ConfirmObject]] = None,
        +        **others: dict,
        +    ):
        +        """An icon button to perform actions.
        +
        +        Args:
        +            action_id: An identifier for this action.
        +                You can use this when you receive an interaction payload to identify the source of the action.
        +                Should be unique among all other action_ids in the containing block.
        +                Maximum length for this field is 255 characters.
        +            icon (required): The icon to show (e.g., 'trash').
        +            text (required): Defines an object containing some text.
        +            accessibility_label: A label for longer descriptive text about a button element.
        +                This label will be read out by screen readers instead of the button text object.
        +                Maximum length for this field is 75 characters.
        +            value: The button value.
        +                Maximum length for this field is 2000 characters.
        +            visible_to_user_ids: User IDs for which the icon appears.
        +                Maximum length for this field is 10 user IDs.
        +            confirm: A confirm object that defines an optional confirmation dialog after the button is clicked.
        +        """
        +        super().__init__(action_id=action_id, type=self.type)
        +        show_unknown_key_warning(self, others)
        +
        +        self.icon = icon
        +        self.text = TextObject.parse(text, PlainTextObject.type)
        +        self.accessibility_label = accessibility_label
        +        self.value = value
        +        self.visible_to_user_ids = visible_to_user_ids
        +        self.confirm = ConfirmObject.parse(confirm) if confirm else None
        +
        +

        Block Elements are things that exists inside of your Blocks. +https://api.slack.com/reference/block-kit/block-elements

        +

        An icon button to perform actions.

        +

        Args

        +
        +
        action_id
        +
        An identifier for this action. +You can use this when you receive an interaction payload to identify the source of the action. +Should be unique among all other action_ids in the containing block. +Maximum length for this field is 255 characters.
        +
        icon : required
        +
        The icon to show (e.g., 'trash').
        +
        text : required
        +
        Defines an object containing some text.
        +
        accessibility_label
        +
        A label for longer descriptive text about a button element. +This label will be read out by screen readers instead of the button text object. +Maximum length for this field is 75 characters.
        +
        value
        +
        The button value. +Maximum length for this field is 2000 characters.
        +
        visible_to_user_ids
        +
        User IDs for which the icon appears. +Maximum length for this field is 10 user IDs.
        +
        confirm
        +
        A confirm object that defines an optional confirmation dialog after the button is clicked.
        +
        +

        Ancestors

        + +

        Class variables

        +
        +
        var type
        +
        +

        The type of the None singleton.

        +
        +
        +

        Inherited members

        + +
        class ImageBlock (*,
        alt_text: str,
        image_url: str | None = None,
        slack_file: Dict[str, Any] | SlackFile | None = None,
        title: str | dict | PlainTextObject | None = None,
        block_id: str | None = None,
        **others: dict)
        @@ -3435,6 +3888,8 @@

        Ancestors

        Subclasses

        • ButtonElement
        • +
        • FeedbackButtonsElement
        • +
        • IconButtonElement
        • InputInteractiveElement
        • OverflowMenuElement
        • WorkflowButtonElement
        • @@ -7443,6 +7898,14 @@

          ContextActionsBlock

          + + +
        • ContextBlock

          • attributes
          • @@ -7514,6 +7977,23 @@

            FeedbackButtonObject

            + + +
          • +

            FeedbackButtonsElement

            + +
          • +
          • FileBlock

            • attributes
            • @@ -7529,6 +8009,12 @@

              IconButtonElement

              + + +
            • ImageBlock

              • alt_text_max_length
              • diff --git a/docs/reference/models/index.html b/docs/reference/models/index.html index 418bd9fa8..3888d29d7 100644 --- a/docs/reference/models/index.html +++ b/docs/reference/models/index.html @@ -298,6 +298,7 @@

                Subclasses

              • AttachmentField
              • ConfirmObject
              • DispatchActionConfig
              • +
              • FeedbackButtonObject
              • Option
              • OptionGroup
              • SlackFile
              • diff --git a/docs/reference/oauth/installation_store/file/index.html b/docs/reference/oauth/installation_store/file/index.html index 1091d3575..7658ddd96 100644 --- a/docs/reference/oauth/installation_store/file/index.html +++ b/docs/reference/oauth/installation_store/file/index.html @@ -48,7 +48,7 @@

                Classes

                class FileInstallationStore -(*,
                base_dir: str = '/Users/michael.brooks/.bolt-app-installation',
                historical_data_enabled: bool = True,
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.installation_store.file (WARNING)>)
                +(*,
                base_dir: str = '/Users/eden.zimbelman/.bolt-app-installation',
                historical_data_enabled: bool = True,
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.installation_store.file (WARNING)>)
                diff --git a/docs/reference/oauth/installation_store/index.html b/docs/reference/oauth/installation_store/index.html index aece243e9..5865522cf 100644 --- a/docs/reference/oauth/installation_store/index.html +++ b/docs/reference/oauth/installation_store/index.html @@ -327,7 +327,7 @@

                Methods

                class FileInstallationStore -(*,
                base_dir: str = '/Users/michael.brooks/.bolt-app-installation',
                historical_data_enabled: bool = True,
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.installation_store.file (WARNING)>)
                +(*,
                base_dir: str = '/Users/eden.zimbelman/.bolt-app-installation',
                historical_data_enabled: bool = True,
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.installation_store.file (WARNING)>)
                diff --git a/docs/reference/oauth/state_store/file/index.html b/docs/reference/oauth/state_store/file/index.html index d91be8db7..33ac16d82 100644 --- a/docs/reference/oauth/state_store/file/index.html +++ b/docs/reference/oauth/state_store/file/index.html @@ -48,7 +48,7 @@

                Classes

                class FileOAuthStateStore -(*,
                expiration_seconds: int,
                base_dir: str = '/Users/michael.brooks/.bolt-app-oauth-state',
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.state_store.file (WARNING)>)
                +(*,
                expiration_seconds: int,
                base_dir: str = '/Users/eden.zimbelman/.bolt-app-oauth-state',
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.state_store.file (WARNING)>)
                diff --git a/docs/reference/oauth/state_store/index.html b/docs/reference/oauth/state_store/index.html index a2f5a251e..efb7d1cfe 100644 --- a/docs/reference/oauth/state_store/index.html +++ b/docs/reference/oauth/state_store/index.html @@ -77,7 +77,7 @@

                Classes

                class FileOAuthStateStore -(*,
                expiration_seconds: int,
                base_dir: str = '/Users/michael.brooks/.bolt-app-oauth-state',
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.state_store.file (WARNING)>)
                +(*,
                expiration_seconds: int,
                base_dir: str = '/Users/eden.zimbelman/.bolt-app-oauth-state',
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.state_store.file (WARNING)>)
                diff --git a/slack_sdk/version.py b/slack_sdk/version.py index db6975baf..bc77fa07f 100644 --- a/slack_sdk/version.py +++ b/slack_sdk/version.py @@ -1,3 +1,3 @@ """Check the latest version at https://pypi.org/project/slack-sdk/""" -__version__ = "3.36.0.dev1" +__version__ = "3.36.0.dev2" From 2ee91df1f560c95f989cb8d27b88c09f8d3e9fac Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 24 Sep 2025 15:21:37 -0700 Subject: [PATCH 09/21] chore(release): version 3.36.0.dev3 --- slack_sdk/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slack_sdk/version.py b/slack_sdk/version.py index bc77fa07f..db4656629 100644 --- a/slack_sdk/version.py +++ b/slack_sdk/version.py @@ -1,3 +1,3 @@ """Check the latest version at https://pypi.org/project/slack-sdk/""" -__version__ = "3.36.0.dev2" +__version__ = "3.36.0.dev3" From 262a7b90097fc51d67fc0477bd83c69de029ea29 Mon Sep 17 00:00:00 2001 From: Michael Brooks Date: Mon, 29 Sep 2025 17:03:43 -0700 Subject: [PATCH 10/21] fix(web-client): update `thread_ts` to be required for `chat_startStream` (#1753) * fix(web-client): update thread_ts arg to be required for chat_startStream method * docs(web-client): generate docs --- docs/reference/index.html | 6 +++--- docs/reference/oauth/installation_store/file/index.html | 2 +- docs/reference/oauth/installation_store/index.html | 2 +- docs/reference/oauth/state_store/file/index.html | 2 +- docs/reference/oauth/state_store/index.html | 2 +- docs/reference/web/async_client.html | 6 +++--- docs/reference/web/client.html | 6 +++--- docs/reference/web/index.html | 6 +++--- docs/reference/web/legacy_client.html | 6 +++--- slack_sdk/web/async_client.py | 2 +- slack_sdk/web/client.py | 2 +- slack_sdk/web/legacy_client.py | 2 +- tests/slack_sdk_async/web/test_web_client_coverage.py | 8 ++++---- 13 files changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/reference/index.html b/docs/reference/index.html index 76ca5c1c4..03a1800e4 100644 --- a/docs/reference/index.html +++ b/docs/reference/index.html @@ -3004,7 +3004,7 @@

                Classes

                self, *, channel: str, - thread_ts: Optional[str] = None, + thread_ts: str, markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, @@ -10268,7 +10268,7 @@

                Methods

                https://api.slack.com/methods/chat.scheduledMessages.list

                -def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str | None = None,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                unfurl_links: bool | None = None,
                unfurl_media: bool | None = None,
                **kwargs) ‑> SlackResponse
                +def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                unfurl_links: bool | None = None,
                unfurl_media: bool | None = None,
                **kwargs) ‑> SlackResponse
                @@ -10279,7 +10279,7 @@

                Methods

                self, *, channel: str, - thread_ts: Optional[str] = None, + thread_ts: str, markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, diff --git a/docs/reference/oauth/installation_store/file/index.html b/docs/reference/oauth/installation_store/file/index.html index 7658ddd96..1091d3575 100644 --- a/docs/reference/oauth/installation_store/file/index.html +++ b/docs/reference/oauth/installation_store/file/index.html @@ -48,7 +48,7 @@

                Classes

                class FileInstallationStore -(*,
                base_dir: str = '/Users/eden.zimbelman/.bolt-app-installation',
                historical_data_enabled: bool = True,
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.installation_store.file (WARNING)>)
                +(*,
                base_dir: str = '/Users/michael.brooks/.bolt-app-installation',
                historical_data_enabled: bool = True,
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.installation_store.file (WARNING)>)
                diff --git a/docs/reference/oauth/installation_store/index.html b/docs/reference/oauth/installation_store/index.html index 5865522cf..aece243e9 100644 --- a/docs/reference/oauth/installation_store/index.html +++ b/docs/reference/oauth/installation_store/index.html @@ -327,7 +327,7 @@

                Methods

                class FileInstallationStore -(*,
                base_dir: str = '/Users/eden.zimbelman/.bolt-app-installation',
                historical_data_enabled: bool = True,
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.installation_store.file (WARNING)>)
                +(*,
                base_dir: str = '/Users/michael.brooks/.bolt-app-installation',
                historical_data_enabled: bool = True,
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.installation_store.file (WARNING)>)
                diff --git a/docs/reference/oauth/state_store/file/index.html b/docs/reference/oauth/state_store/file/index.html index 33ac16d82..d91be8db7 100644 --- a/docs/reference/oauth/state_store/file/index.html +++ b/docs/reference/oauth/state_store/file/index.html @@ -48,7 +48,7 @@

                Classes

                class FileOAuthStateStore -(*,
                expiration_seconds: int,
                base_dir: str = '/Users/eden.zimbelman/.bolt-app-oauth-state',
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.state_store.file (WARNING)>)
                +(*,
                expiration_seconds: int,
                base_dir: str = '/Users/michael.brooks/.bolt-app-oauth-state',
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.state_store.file (WARNING)>)
                diff --git a/docs/reference/oauth/state_store/index.html b/docs/reference/oauth/state_store/index.html index efb7d1cfe..a2f5a251e 100644 --- a/docs/reference/oauth/state_store/index.html +++ b/docs/reference/oauth/state_store/index.html @@ -77,7 +77,7 @@

                Classes

                class FileOAuthStateStore -(*,
                expiration_seconds: int,
                base_dir: str = '/Users/eden.zimbelman/.bolt-app-oauth-state',
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.state_store.file (WARNING)>)
                +(*,
                expiration_seconds: int,
                base_dir: str = '/Users/michael.brooks/.bolt-app-oauth-state',
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.state_store.file (WARNING)>)
                diff --git a/docs/reference/web/async_client.html b/docs/reference/web/async_client.html index e87f65501..a75296b83 100644 --- a/docs/reference/web/async_client.html +++ b/docs/reference/web/async_client.html @@ -2900,7 +2900,7 @@

                Classes

                self, *, channel: str, - thread_ts: Optional[str] = None, + thread_ts: str, markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, @@ -10164,7 +10164,7 @@

                Methods

                https://api.slack.com/methods/chat.scheduledMessages.list

                -async def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str | None = None,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                unfurl_links: bool | None = None,
                unfurl_media: bool | None = None,
                **kwargs) ‑> AsyncSlackResponse
                +async def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                unfurl_links: bool | None = None,
                unfurl_media: bool | None = None,
                **kwargs) ‑> AsyncSlackResponse
                @@ -10175,7 +10175,7 @@

                Methods

                self, *, channel: str, - thread_ts: Optional[str] = None, + thread_ts: str, markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, diff --git a/docs/reference/web/client.html b/docs/reference/web/client.html index a6c282b42..b2d44f9ee 100644 --- a/docs/reference/web/client.html +++ b/docs/reference/web/client.html @@ -2900,7 +2900,7 @@

                Classes

                self, *, channel: str, - thread_ts: Optional[str] = None, + thread_ts: str, markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, @@ -10164,7 +10164,7 @@

                Methods

                https://api.slack.com/methods/chat.scheduledMessages.list

                -def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str | None = None,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                unfurl_links: bool | None = None,
                unfurl_media: bool | None = None,
                **kwargs) ‑> SlackResponse
                +def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                unfurl_links: bool | None = None,
                unfurl_media: bool | None = None,
                **kwargs) ‑> SlackResponse
                @@ -10175,7 +10175,7 @@

                Methods

                self, *, channel: str, - thread_ts: Optional[str] = None, + thread_ts: str, markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, diff --git a/docs/reference/web/index.html b/docs/reference/web/index.html index 1e49e8dda..17315ee92 100644 --- a/docs/reference/web/index.html +++ b/docs/reference/web/index.html @@ -3261,7 +3261,7 @@

                Raises

                self, *, channel: str, - thread_ts: Optional[str] = None, + thread_ts: str, markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, @@ -10525,7 +10525,7 @@

                Methods

                https://api.slack.com/methods/chat.scheduledMessages.list

                -def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str | None = None,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                unfurl_links: bool | None = None,
                unfurl_media: bool | None = None,
                **kwargs) ‑> SlackResponse
                +def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                unfurl_links: bool | None = None,
                unfurl_media: bool | None = None,
                **kwargs) ‑> SlackResponse
                @@ -10536,7 +10536,7 @@

                Methods

                self, *, channel: str, - thread_ts: Optional[str] = None, + thread_ts: str, markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, diff --git a/docs/reference/web/legacy_client.html b/docs/reference/web/legacy_client.html index 1cc442667..ad9ae4b96 100644 --- a/docs/reference/web/legacy_client.html +++ b/docs/reference/web/legacy_client.html @@ -2899,7 +2899,7 @@

                Classes

                self, *, channel: str, - thread_ts: Optional[str] = None, + thread_ts: str, markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, @@ -10163,7 +10163,7 @@

                Methods

                https://api.slack.com/methods/chat.scheduledMessages.list

                -def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str | None = None,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                unfurl_links: bool | None = None,
                unfurl_media: bool | None = None,
                **kwargs) ‑> _asyncio.Future | LegacySlackResponse
                +def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                unfurl_links: bool | None = None,
                unfurl_media: bool | None = None,
                **kwargs) ‑> _asyncio.Future | LegacySlackResponse
                @@ -10174,7 +10174,7 @@

                Methods

                self, *, channel: str, - thread_ts: Optional[str] = None, + thread_ts: str, markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, diff --git a/slack_sdk/web/async_client.py b/slack_sdk/web/async_client.py index 84a490920..5b4a474ac 100644 --- a/slack_sdk/web/async_client.py +++ b/slack_sdk/web/async_client.py @@ -2878,7 +2878,7 @@ async def chat_startStream( self, *, channel: str, - thread_ts: Optional[str] = None, + thread_ts: str, markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, diff --git a/slack_sdk/web/client.py b/slack_sdk/web/client.py index cdce5f975..fa9683b13 100644 --- a/slack_sdk/web/client.py +++ b/slack_sdk/web/client.py @@ -2868,7 +2868,7 @@ def chat_startStream( self, *, channel: str, - thread_ts: Optional[str] = None, + thread_ts: str, markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, diff --git a/slack_sdk/web/legacy_client.py b/slack_sdk/web/legacy_client.py index 10d2c7afb..558598806 100644 --- a/slack_sdk/web/legacy_client.py +++ b/slack_sdk/web/legacy_client.py @@ -2880,7 +2880,7 @@ def chat_startStream( self, *, channel: str, - thread_ts: Optional[str] = None, + thread_ts: str, markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, diff --git a/tests/slack_sdk_async/web/test_web_client_coverage.py b/tests/slack_sdk_async/web/test_web_client_coverage.py index d7451dd7d..998c0bb3e 100644 --- a/tests/slack_sdk_async/web/test_web_client_coverage.py +++ b/tests/slack_sdk_async/web/test_web_client_coverage.py @@ -568,10 +568,10 @@ async def run_method(self, method_name, method, async_method): self.api_methods_to_call.remove(method()["method"]) await async_method() elif method_name == "chat_startStream": - self.api_methods_to_call.remove(method(channel="C123")["method"]) - method(channel="C123", recipient_team_id="T123", recipient_user_id="U123") - await async_method(channel="C123") - await async_method(channel="C123", recipient_team_id="T123", recipient_user_id="U123") + self.api_methods_to_call.remove(method(channel="C123", thread_ts="123.123")["method"]) + await async_method(channel="C123", thread_ts="123.123") + method(channel="C123", thread_ts="123.123", recipient_team_id="T123", recipient_user_id="U123") + await async_method(channel="C123", thread_ts="123.123", recipient_team_id="T123", recipient_user_id="U123") elif method_name == "chat_stopStream": self.api_methods_to_call.remove( method(channel="C123", ts="123.123", blocks=[{"type": "markdown", "text": "**twelve**"}])["method"] From f901e2597f70e3ca7bd00aef60a87eb2e06480c1 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 30 Sep 2025 11:01:35 -0700 Subject: [PATCH 11/21] chore: bump to aiAppsBeta.4 --- docs/reference/oauth/installation_store/file/index.html | 2 +- docs/reference/oauth/installation_store/index.html | 2 +- docs/reference/oauth/state_store/file/index.html | 2 +- docs/reference/oauth/state_store/index.html | 2 +- slack_sdk/version.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/reference/oauth/installation_store/file/index.html b/docs/reference/oauth/installation_store/file/index.html index 1091d3575..7658ddd96 100644 --- a/docs/reference/oauth/installation_store/file/index.html +++ b/docs/reference/oauth/installation_store/file/index.html @@ -48,7 +48,7 @@

                Classes

                class FileInstallationStore -(*,
                base_dir: str = '/Users/michael.brooks/.bolt-app-installation',
                historical_data_enabled: bool = True,
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.installation_store.file (WARNING)>)
                +(*,
                base_dir: str = '/Users/eden.zimbelman/.bolt-app-installation',
                historical_data_enabled: bool = True,
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.installation_store.file (WARNING)>)
                diff --git a/docs/reference/oauth/installation_store/index.html b/docs/reference/oauth/installation_store/index.html index aece243e9..5865522cf 100644 --- a/docs/reference/oauth/installation_store/index.html +++ b/docs/reference/oauth/installation_store/index.html @@ -327,7 +327,7 @@

                Methods

                class FileInstallationStore -(*,
                base_dir: str = '/Users/michael.brooks/.bolt-app-installation',
                historical_data_enabled: bool = True,
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.installation_store.file (WARNING)>)
                +(*,
                base_dir: str = '/Users/eden.zimbelman/.bolt-app-installation',
                historical_data_enabled: bool = True,
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.installation_store.file (WARNING)>)
                diff --git a/docs/reference/oauth/state_store/file/index.html b/docs/reference/oauth/state_store/file/index.html index d91be8db7..33ac16d82 100644 --- a/docs/reference/oauth/state_store/file/index.html +++ b/docs/reference/oauth/state_store/file/index.html @@ -48,7 +48,7 @@

                Classes

                class FileOAuthStateStore -(*,
                expiration_seconds: int,
                base_dir: str = '/Users/michael.brooks/.bolt-app-oauth-state',
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.state_store.file (WARNING)>)
                +(*,
                expiration_seconds: int,
                base_dir: str = '/Users/eden.zimbelman/.bolt-app-oauth-state',
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.state_store.file (WARNING)>)
                diff --git a/docs/reference/oauth/state_store/index.html b/docs/reference/oauth/state_store/index.html index a2f5a251e..efb7d1cfe 100644 --- a/docs/reference/oauth/state_store/index.html +++ b/docs/reference/oauth/state_store/index.html @@ -77,7 +77,7 @@

                Classes

                class FileOAuthStateStore -(*,
                expiration_seconds: int,
                base_dir: str = '/Users/michael.brooks/.bolt-app-oauth-state',
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.state_store.file (WARNING)>)
                +(*,
                expiration_seconds: int,
                base_dir: str = '/Users/eden.zimbelman/.bolt-app-oauth-state',
                client_id: str | None = None,
                logger: logging.Logger = <Logger slack_sdk.oauth.state_store.file (WARNING)>)
                diff --git a/slack_sdk/version.py b/slack_sdk/version.py index db4656629..cde8e8bf0 100644 --- a/slack_sdk/version.py +++ b/slack_sdk/version.py @@ -1,3 +1,3 @@ """Check the latest version at https://pypi.org/project/slack-sdk/""" -__version__ = "3.36.0.dev3" +__version__ = "3.36.0.dev4" From 829d4097f72fb07f88da8f4759e71208d7a36209 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 30 Sep 2025 11:18:40 -0700 Subject: [PATCH 12/21] fix(web): send structured values to "assistant.threads.setStatus" method using json content type (#1754) Co-authored-by: Michael Brooks --- docs/reference/index.html | 6 ++++-- docs/reference/web/async_client.html | 6 ++++-- docs/reference/web/client.html | 6 ++++-- docs/reference/web/index.html | 6 ++++-- docs/reference/web/legacy_client.html | 6 ++++-- slack_sdk/web/async_client.py | 3 ++- slack_sdk/web/client.py | 3 ++- slack_sdk/web/legacy_client.py | 3 ++- .../slack_sdk_async/web/test_web_client_coverage.py | 12 ++++++++++++ 9 files changed, 38 insertions(+), 13 deletions(-) diff --git a/docs/reference/index.html b/docs/reference/index.html index 03a1800e4..0245eb5ff 100644 --- a/docs/reference/index.html +++ b/docs/reference/index.html @@ -2210,7 +2210,8 @@

                Classes

                kwargs.update( {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} ) - return self.api_call("assistant.threads.setStatus", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("assistant.threads.setStatus", json=kwargs) def assistant_threads_setTitle( self, @@ -8991,7 +8992,8 @@

                Methods

                kwargs.update( {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} ) - return self.api_call("assistant.threads.setStatus", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("assistant.threads.setStatus", json=kwargs)

                Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus

                diff --git a/docs/reference/web/async_client.html b/docs/reference/web/async_client.html index a75296b83..9d895fea8 100644 --- a/docs/reference/web/async_client.html +++ b/docs/reference/web/async_client.html @@ -2106,7 +2106,8 @@

                Classes

                kwargs.update( {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} ) - return await self.api_call("assistant.threads.setStatus", params=kwargs) + kwargs = _remove_none_values(kwargs) + return await self.api_call("assistant.threads.setStatus", json=kwargs) async def assistant_threads_setTitle( self, @@ -8887,7 +8888,8 @@

                Methods

                kwargs.update( {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} ) - return await self.api_call("assistant.threads.setStatus", params=kwargs) + kwargs = _remove_none_values(kwargs) + return await self.api_call("assistant.threads.setStatus", json=kwargs)

                Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus

                diff --git a/docs/reference/web/client.html b/docs/reference/web/client.html index b2d44f9ee..e6704424c 100644 --- a/docs/reference/web/client.html +++ b/docs/reference/web/client.html @@ -2106,7 +2106,8 @@

                Classes

                kwargs.update( {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} ) - return self.api_call("assistant.threads.setStatus", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("assistant.threads.setStatus", json=kwargs) def assistant_threads_setTitle( self, @@ -8887,7 +8888,8 @@

                Methods

                kwargs.update( {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} ) - return self.api_call("assistant.threads.setStatus", params=kwargs)
                + kwargs = _remove_none_values(kwargs) + return self.api_call("assistant.threads.setStatus", json=kwargs)

                Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus

                diff --git a/docs/reference/web/index.html b/docs/reference/web/index.html index 17315ee92..2e9c01af9 100644 --- a/docs/reference/web/index.html +++ b/docs/reference/web/index.html @@ -2467,7 +2467,8 @@

                Raises

                kwargs.update( {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} ) - return self.api_call("assistant.threads.setStatus", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("assistant.threads.setStatus", json=kwargs) def assistant_threads_setTitle( self, @@ -9248,7 +9249,8 @@

                Methods

                kwargs.update( {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} ) - return self.api_call("assistant.threads.setStatus", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("assistant.threads.setStatus", json=kwargs)

                Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus

                diff --git a/docs/reference/web/legacy_client.html b/docs/reference/web/legacy_client.html index ad9ae4b96..1d4ebbed8 100644 --- a/docs/reference/web/legacy_client.html +++ b/docs/reference/web/legacy_client.html @@ -2105,7 +2105,8 @@

                Classes

                kwargs.update( {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} ) - return self.api_call("assistant.threads.setStatus", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("assistant.threads.setStatus", json=kwargs) def assistant_threads_setTitle( self, @@ -8886,7 +8887,8 @@

                Methods

                kwargs.update( {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} ) - return self.api_call("assistant.threads.setStatus", params=kwargs)
                + kwargs = _remove_none_values(kwargs) + return self.api_call("assistant.threads.setStatus", json=kwargs)

                Set the status for an AI assistant thread. https://api.slack.com/methods/assistant.threads.setStatus

                diff --git a/slack_sdk/web/async_client.py b/slack_sdk/web/async_client.py index 5b4a474ac..3f30bad5a 100644 --- a/slack_sdk/web/async_client.py +++ b/slack_sdk/web/async_client.py @@ -2084,7 +2084,8 @@ async def assistant_threads_setStatus( kwargs.update( {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} ) - return await self.api_call("assistant.threads.setStatus", params=kwargs) + kwargs = _remove_none_values(kwargs) + return await self.api_call("assistant.threads.setStatus", json=kwargs) async def assistant_threads_setTitle( self, diff --git a/slack_sdk/web/client.py b/slack_sdk/web/client.py index fa9683b13..8c15f983f 100644 --- a/slack_sdk/web/client.py +++ b/slack_sdk/web/client.py @@ -2074,7 +2074,8 @@ def assistant_threads_setStatus( kwargs.update( {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} ) - return self.api_call("assistant.threads.setStatus", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("assistant.threads.setStatus", json=kwargs) def assistant_threads_setTitle( self, diff --git a/slack_sdk/web/legacy_client.py b/slack_sdk/web/legacy_client.py index 558598806..29ef99064 100644 --- a/slack_sdk/web/legacy_client.py +++ b/slack_sdk/web/legacy_client.py @@ -2086,7 +2086,8 @@ def assistant_threads_setStatus( kwargs.update( {"channel_id": channel_id, "thread_ts": thread_ts, "status": status, "loading_messages": loading_messages} ) - return self.api_call("assistant.threads.setStatus", params=kwargs) + kwargs = _remove_none_values(kwargs) + return self.api_call("assistant.threads.setStatus", json=kwargs) def assistant_threads_setTitle( self, diff --git a/tests/slack_sdk_async/web/test_web_client_coverage.py b/tests/slack_sdk_async/web/test_web_client_coverage.py index 998c0bb3e..af6d92236 100644 --- a/tests/slack_sdk_async/web/test_web_client_coverage.py +++ b/tests/slack_sdk_async/web/test_web_client_coverage.py @@ -425,7 +425,19 @@ async def run_method(self, method_name, method, async_method): self.api_methods_to_call.remove( method(channel_id="D111", thread_ts="111.222", status="is typing...")["method"] ) + method( + channel_id="D111", + thread_ts="111.222", + status="is typing...", + loading_states=["Thinking...", "Writing..."], + ) await async_method(channel_id="D111", thread_ts="111.222", status="is typing...") + await async_method( + channel_id="D111", + thread_ts="111.222", + status="is typing...", + loading_states=["Thinking...", "Writing..."], + ) elif method_name == "assistant_threads_setTitle": self.api_methods_to_call.remove(method(channel_id="D111", thread_ts="111.222", title="New chat")["method"]) await async_method(channel_id="D111", thread_ts="111.222", title="New chat") From bd1857fb216fa3fc8bfb20cfd94c6caa2e655683 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 30 Sep 2025 11:23:45 -0700 Subject: [PATCH 13/21] chore: bump to aiAppsBeta.5 --- slack_sdk/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slack_sdk/version.py b/slack_sdk/version.py index cde8e8bf0..95e0f5493 100644 --- a/slack_sdk/version.py +++ b/slack_sdk/version.py @@ -1,3 +1,3 @@ """Check the latest version at https://pypi.org/project/slack-sdk/""" -__version__ = "3.36.0.dev4" +__version__ = "3.36.0.dev5" From 64a995c1d10175d5305ab740bd0b57e97087007a Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Thu, 2 Oct 2025 10:10:30 -0700 Subject: [PATCH 14/21] feat(web-api): add a chat stream method to the web client (#1755) Co-authored-by: Michael Brooks --- docs/reference/index.html | 180 +++++++ docs/reference/web/async_chat_stream.html | 506 ++++++++++++++++++ docs/reference/web/async_client.html | 180 +++++++ docs/reference/web/chat_stream.html | 506 ++++++++++++++++++ docs/reference/web/client.html | 180 +++++++ docs/reference/web/index.html | 190 +++++++ scripts/codegen.py | 55 +- slack_sdk/web/async_chat_stream.py | 212 ++++++++ slack_sdk/web/async_client.py | 64 +++ slack_sdk/web/chat_stream.py | 202 +++++++ slack_sdk/web/client.py | 64 +++ tests/slack_sdk/web/test_chat_stream.py | 188 +++++++ .../web/test_async_chat_stream.py | 193 +++++++ .../web_response_chat_stream_test.json | 4 + ..._response_chat_stream_test_missing_ts.json | 3 + .../web_response_chat_stream_test_token1.json | 3 + .../web_response_chat_stream_test_token2.json | 3 + 17 files changed, 2731 insertions(+), 2 deletions(-) create mode 100644 docs/reference/web/async_chat_stream.html create mode 100644 docs/reference/web/chat_stream.html create mode 100644 slack_sdk/web/async_chat_stream.py create mode 100644 slack_sdk/web/chat_stream.py create mode 100644 tests/slack_sdk/web/test_chat_stream.py create mode 100644 tests/slack_sdk_async/web/test_async_chat_stream.py create mode 100644 tests/slack_sdk_fixture/web_response_chat_stream_test.json create mode 100644 tests/slack_sdk_fixture/web_response_chat_stream_test_missing_ts.json create mode 100644 tests/slack_sdk_fixture/web_response_chat_stream_test_token1.json create mode 100644 tests/slack_sdk_fixture/web_response_chat_stream_test_token2.json diff --git a/docs/reference/index.html b/docs/reference/index.html index 0245eb5ff..3cfd45f3f 100644 --- a/docs/reference/index.html +++ b/docs/reference/index.html @@ -3056,6 +3056,69 @@

                Classes

                kwargs = _remove_none_values(kwargs) return self.api_call("chat.stopStream", json=kwargs) + def chat_stream( + self, + *, + buffer_size: int = 256, + channel: str, + thread_ts: str, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, + **kwargs, + ) -> ChatStream: + """Stream markdown text into a conversation. + + This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, + the stream can be stopped with concluding arguments such as "blocks" for gathering feedback. + + The following methods are used: + + - chat.startStream: Starts a new streaming conversation. + [Reference](https://docs.slack.dev/reference/methods/chat.startStream). + - chat.appendStream: Appends text to an existing streaming conversation. + [Reference](https://docs.slack.dev/reference/methods/chat.appendStream). + - chat.stopStream: Stops a streaming conversation. + [Reference](https://docs.slack.dev/reference/methods/chat.stopStream). + + Args: + buffer_size: The length of markdown_text to buffer in-memory before calling a stream method. Increasing this + value decreases the number of method calls made for the same amount of text, which is useful to avoid rate + limits. Default: 256. + channel: An encoded ID that represents a channel, private group, or DM. + thread_ts: Provide another message's ts value to reply to. Streamed messages should always be replies to a user + request. + recipient_team_id: The encoded ID of the team the user receiving the streaming text belongs to. Required when + streaming to channels. + recipient_user_id: The encoded ID of the user to receive the streaming text. Required when streaming to channels. + **kwargs: Additional arguments passed to the underlying API calls. + + Returns: + ChatStream instance for managing the stream + + Example: + ```python + streamer = client.chat_stream( + channel="C0123456789", + thread_ts="1700000001.123456", + recipient_team_id="T0123456789", + recipient_user_id="U0123456789", + ) + streamer.append(markdown_text="**hello wo") + streamer.append(markdown_text="rld!**") + streamer.stop() + ``` + """ + return ChatStream( + self, + logger=self._logger, + channel=channel, + thread_ts=thread_ts, + recipient_team_id=recipient_team_id, + recipient_user_id=recipient_user_id, + buffer_size=buffer_size, + **kwargs, + ) + def chat_unfurl( self, *, @@ -10346,6 +10409,122 @@

                Methods

                Stops a streaming conversation. https://api.slack.com/methods/chat.stopStream

                +
                +def chat_stream(self,
                *,
                buffer_size: int = 256,
                channel: str,
                thread_ts: str,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                **kwargs) ‑> ChatStream
                +
                +
                +
                + +Expand source code + +
                def chat_stream(
                +    self,
                +    *,
                +    buffer_size: int = 256,
                +    channel: str,
                +    thread_ts: str,
                +    recipient_team_id: Optional[str] = None,
                +    recipient_user_id: Optional[str] = None,
                +    **kwargs,
                +) -> ChatStream:
                +    """Stream markdown text into a conversation.
                +
                +    This method starts a new chat stream in a coversation that can be appended to. After appending an entire message,
                +    the stream can be stopped with concluding arguments such as "blocks" for gathering feedback.
                +
                +    The following methods are used:
                +
                +    - chat.startStream: Starts a new streaming conversation.
                +      [Reference](https://docs.slack.dev/reference/methods/chat.startStream).
                +    - chat.appendStream: Appends text to an existing streaming conversation.
                +      [Reference](https://docs.slack.dev/reference/methods/chat.appendStream).
                +    - chat.stopStream: Stops a streaming conversation.
                +      [Reference](https://docs.slack.dev/reference/methods/chat.stopStream).
                +
                +    Args:
                +        buffer_size: The length of markdown_text to buffer in-memory before calling a stream method. Increasing this
                +          value decreases the number of method calls made for the same amount of text, which is useful to avoid rate
                +          limits. Default: 256.
                +        channel: An encoded ID that represents a channel, private group, or DM.
                +        thread_ts: Provide another message's ts value to reply to. Streamed messages should always be replies to a user
                +          request.
                +        recipient_team_id: The encoded ID of the team the user receiving the streaming text belongs to. Required when
                +          streaming to channels.
                +        recipient_user_id: The encoded ID of the user to receive the streaming text. Required when streaming to channels.
                +        **kwargs: Additional arguments passed to the underlying API calls.
                +
                +    Returns:
                +        ChatStream instance for managing the stream
                +
                +    Example:
                +        ```python
                +        streamer = client.chat_stream(
                +            channel="C0123456789",
                +            thread_ts="1700000001.123456",
                +            recipient_team_id="T0123456789",
                +            recipient_user_id="U0123456789",
                +        )
                +        streamer.append(markdown_text="**hello wo")
                +        streamer.append(markdown_text="rld!**")
                +        streamer.stop()
                +        ```
                +    """
                +    return ChatStream(
                +        self,
                +        logger=self._logger,
                +        channel=channel,
                +        thread_ts=thread_ts,
                +        recipient_team_id=recipient_team_id,
                +        recipient_user_id=recipient_user_id,
                +        buffer_size=buffer_size,
                +        **kwargs,
                +    )
                +
                +

                Stream markdown text into a conversation.

                +

                This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, +the stream can be stopped with concluding arguments such as "blocks" for gathering feedback.

                +

                The following methods are used:

                +
                  +
                • chat.startStream: Starts a new streaming conversation. +Reference.
                • +
                • chat.appendStream: Appends text to an existing streaming conversation. +Reference.
                • +
                • chat.stopStream: Stops a streaming conversation. +Reference.
                • +
                +

                Args

                +
                +
                buffer_size
                +
                The length of markdown_text to buffer in-memory before calling a stream method. Increasing this +value decreases the number of method calls made for the same amount of text, which is useful to avoid rate +limits. Default: 256.
                +
                channel
                +
                An encoded ID that represents a channel, private group, or DM.
                +
                thread_ts
                +
                Provide another message's ts value to reply to. Streamed messages should always be replies to a user +request.
                +
                recipient_team_id
                +
                The encoded ID of the team the user receiving the streaming text belongs to. Required when +streaming to channels.
                +
                recipient_user_id
                +
                The encoded ID of the user to receive the streaming text. Required when streaming to channels.
                +
                **kwargs
                +
                Additional arguments passed to the underlying API calls.
                +
                +

                Returns

                +

                ChatStream instance for managing the stream

                +

                Example

                +
                streamer = client.chat_stream(
                +    channel="C0123456789",
                +    thread_ts="1700000001.123456",
                +    recipient_team_id="T0123456789",
                +    recipient_user_id="U0123456789",
                +)
                +streamer.append(markdown_text="**hello wo")
                +streamer.append(markdown_text="rld!**")
                +streamer.stop()
                +
                +
                def chat_unfurl(self,
                *,
                channel: str | None = None,
                ts: str | None = None,
                source: str | None = None,
                unfurl_id: str | None = None,
                unfurls: Dict[str, Dict] | None = None,
                user_auth_blocks: str | Sequence[Dict | Block] | None = None,
                user_auth_message: str | None = None,
                user_auth_required: bool | None = None,
                user_auth_url: str | None = None,
                **kwargs) ‑> SlackResponse
                @@ -15323,6 +15502,7 @@

                WebClientchat_scheduledMessages_list
              • chat_startStream
              • chat_stopStream
              • +
              • chat_stream
              • chat_unfurl
              • chat_update
              • conversations_acceptSharedInvite
              • diff --git a/docs/reference/web/async_chat_stream.html b/docs/reference/web/async_chat_stream.html new file mode 100644 index 000000000..ca7bf2506 --- /dev/null +++ b/docs/reference/web/async_chat_stream.html @@ -0,0 +1,506 @@ + + + + + + +slack_sdk.web.async_chat_stream API documentation + + + + + + + + + + + +
                +
                +
                +

                Module slack_sdk.web.async_chat_stream

                +
                +
                +
                +
                +
                +
                +
                +
                +
                +
                +

                Classes

                +
                +
                +class AsyncChatStream +(client: AsyncWebClient,
                *,
                channel: str,
                logger: logging.Logger,
                thread_ts: str,
                buffer_size: int,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                **kwargs)
                +
                +
                +
                + +Expand source code + +
                class AsyncChatStream:
                +    """A helper class for streaming markdown text into a conversation using the chat streaming APIs.
                +
                +    This class provides a convenient interface for the chat.startStream, chat.appendStream, and chat.stopStream API
                +    methods, with automatic buffering and state management.
                +    """
                +
                +    def __init__(
                +        self,
                +        client: "AsyncWebClient",
                +        *,
                +        channel: str,
                +        logger: logging.Logger,
                +        thread_ts: str,
                +        buffer_size: int,
                +        recipient_team_id: Optional[str] = None,
                +        recipient_user_id: Optional[str] = None,
                +        **kwargs,
                +    ):
                +        """Initialize a new ChatStream instance.
                +
                +        The __init__ method creates a unique ChatStream instance that keeps track of one chat stream.
                +
                +        Args:
                +            client: The WebClient instance to use for API calls.
                +            channel: An encoded ID that represents a channel, private group, or DM.
                +            logger: A logging channel for outputs.
                +            thread_ts: Provide another message's ts value to reply to. Streamed messages should always be replies to a user
                +              request.
                +            recipient_team_id: The encoded ID of the team the user receiving the streaming text belongs to. Required when
                +              streaming to channels.
                +            recipient_user_id: The encoded ID of the user to receive the streaming text. Required when streaming to channels.
                +            buffer_size: The length of markdown_text to buffer in-memory before calling a method. Increasing this value
                +              decreases the number of method calls made for the same amount of text, which is useful to avoid rate limits.
                +            **kwargs: Additional arguments passed to the underlying API calls.
                +        """
                +        self._client = client
                +        self._logger = logger
                +        self._token: Optional[str] = kwargs.pop("token", None)
                +        self._stream_args = {
                +            "channel": channel,
                +            "thread_ts": thread_ts,
                +            "recipient_team_id": recipient_team_id,
                +            "recipient_user_id": recipient_user_id,
                +            **kwargs,
                +        }
                +        self._buffer = ""
                +        self._state = "starting"
                +        self._stream_ts: Optional[str] = None
                +        self._buffer_size = buffer_size
                +
                +    async def append(
                +        self,
                +        *,
                +        markdown_text: str,
                +        **kwargs,
                +    ) -> Optional[AsyncSlackResponse]:
                +        """Append to the stream.
                +
                +        The "append" method appends to the chat stream being used. This method can be called multiple times. After the stream
                +        is stopped this method cannot be called.
                +
                +        Args:
                +            markdown_text: Accepts message text formatted in markdown. Limit this field to 12,000 characters. This text is
                +              what will be appended to the message received so far.
                +            **kwargs: Additional arguments passed to the underlying API calls.
                +
                +        Returns:
                +            AsyncSlackResponse if the buffer was flushed, None if buffering.
                +
                +        Raises:
                +            SlackRequestError: If the stream is already completed.
                +
                +        Example:
                +            ```python
                +            streamer = client.chat_stream(
                +                channel="C0123456789",
                +                thread_ts="1700000001.123456",
                +                recipient_team_id="T0123456789",
                +                recipient_user_id="U0123456789",
                +            )
                +            streamer.append(markdown_text="**hello wo")
                +            streamer.append(markdown_text="rld!**")
                +            streamer.stop()
                +            ```
                +        """
                +        if self._state == "completed":
                +            raise e.SlackRequestError(f"Cannot append to stream: stream state is {self._state}")
                +        if kwargs.get("token"):
                +            self._token = kwargs.pop("token")
                +        self._buffer += markdown_text
                +        if len(self._buffer) >= self._buffer_size:
                +            return await self._flush_buffer(**kwargs)
                +        details = {
                +            "buffer_length": len(self._buffer),
                +            "buffer_size": self._buffer_size,
                +            "channel": self._stream_args.get("channel"),
                +            "recipient_team_id": self._stream_args.get("recipient_team_id"),
                +            "recipient_user_id": self._stream_args.get("recipient_user_id"),
                +            "thread_ts": self._stream_args.get("thread_ts"),
                +        }
                +        self._logger.debug(f"ChatStream appended to buffer: {json.dumps(details)}")
                +        return None
                +
                +    async def stop(
                +        self,
                +        *,
                +        markdown_text: Optional[str] = None,
                +        blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None,
                +        metadata: Optional[Union[Dict, Metadata]] = None,
                +        **kwargs,
                +    ) -> AsyncSlackResponse:
                +        """Stop the stream and finalize the message.
                +
                +        Args:
                +            blocks: A list of blocks that will be rendered at the bottom of the finalized message.
                +            markdown_text: Accepts message text formatted in markdown. Limit this field to 12,000 characters. This text is
                +              what will be appended to the message received so far.
                +            metadata: JSON object with event_type and event_payload fields, presented as a URL-encoded string. Metadata you
                +              post to Slack is accessible to any app or user who is a member of that workspace.
                +            **kwargs: Additional arguments passed to the underlying API calls.
                +
                +        Returns:
                +            AsyncSlackResponse from the chat.stopStream API call.
                +
                +        Raises:
                +            SlackRequestError: If the stream is already completed.
                +
                +        Example:
                +            ```python
                +            streamer = client.chat_stream(
                +                channel="C0123456789",
                +                thread_ts="1700000001.123456",
                +                recipient_team_id="T0123456789",
                +                recipient_user_id="U0123456789",
                +            )
                +            streamer.append(markdown_text="**hello wo")
                +            streamer.append(markdown_text="rld!**")
                +            streamer.stop()
                +            ```
                +        """
                +        if self._state == "completed":
                +            raise e.SlackRequestError(f"Cannot stop stream: stream state is {self._state}")
                +        if kwargs.get("token"):
                +            self._token = kwargs.pop("token")
                +        if markdown_text:
                +            self._buffer += markdown_text
                +        if not self._stream_ts:
                +            response = await self._client.chat_startStream(
                +                **self._stream_args,
                +                token=self._token,
                +            )
                +            if not response.get("ts"):
                +                raise e.SlackRequestError("Failed to stop stream: stream not started")
                +            self._stream_ts = str(response["ts"])
                +            self._state = "in_progress"
                +        response = await self._client.chat_stopStream(
                +            token=self._token,
                +            channel=self._stream_args["channel"],
                +            ts=self._stream_ts,
                +            blocks=blocks,
                +            markdown_text=self._buffer,
                +            metadata=metadata,
                +            **kwargs,
                +        )
                +        self._state = "completed"
                +        return response
                +
                +    async def _flush_buffer(self, **kwargs) -> AsyncSlackResponse:
                +        """Flush the internal buffer by making appropriate API calls."""
                +        if not self._stream_ts:
                +            response = await self._client.chat_startStream(
                +                **self._stream_args,
                +                token=self._token,
                +                **kwargs,
                +                markdown_text=self._buffer,
                +            )
                +            self._stream_ts = response.get("ts")
                +            self._state = "in_progress"
                +        else:
                +            response = await self._client.chat_appendStream(
                +                token=self._token,
                +                channel=self._stream_args["channel"],
                +                ts=self._stream_ts,
                +                **kwargs,
                +                markdown_text=self._buffer,
                +            )
                +        self._buffer = ""
                +        return response
                +
                +

                A helper class for streaming markdown text into a conversation using the chat streaming APIs.

                +

                This class provides a convenient interface for the chat.startStream, chat.appendStream, and chat.stopStream API +methods, with automatic buffering and state management.

                +

                Initialize a new ChatStream instance.

                +

                The init method creates a unique ChatStream instance that keeps track of one chat stream.

                +

                Args

                +
                +
                client
                +
                The WebClient instance to use for API calls.
                +
                channel
                +
                An encoded ID that represents a channel, private group, or DM.
                +
                logger
                +
                A logging channel for outputs.
                +
                thread_ts
                +
                Provide another message's ts value to reply to. Streamed messages should always be replies to a user +request.
                +
                recipient_team_id
                +
                The encoded ID of the team the user receiving the streaming text belongs to. Required when +streaming to channels.
                +
                recipient_user_id
                +
                The encoded ID of the user to receive the streaming text. Required when streaming to channels.
                +
                buffer_size
                +
                The length of markdown_text to buffer in-memory before calling a method. Increasing this value +decreases the number of method calls made for the same amount of text, which is useful to avoid rate limits.
                +
                **kwargs
                +
                Additional arguments passed to the underlying API calls.
                +
                +

                Methods

                +
                +
                +async def append(self, *, markdown_text: str, **kwargs) ‑> AsyncSlackResponse | None +
                +
                +
                + +Expand source code + +
                async def append(
                +    self,
                +    *,
                +    markdown_text: str,
                +    **kwargs,
                +) -> Optional[AsyncSlackResponse]:
                +    """Append to the stream.
                +
                +    The "append" method appends to the chat stream being used. This method can be called multiple times. After the stream
                +    is stopped this method cannot be called.
                +
                +    Args:
                +        markdown_text: Accepts message text formatted in markdown. Limit this field to 12,000 characters. This text is
                +          what will be appended to the message received so far.
                +        **kwargs: Additional arguments passed to the underlying API calls.
                +
                +    Returns:
                +        AsyncSlackResponse if the buffer was flushed, None if buffering.
                +
                +    Raises:
                +        SlackRequestError: If the stream is already completed.
                +
                +    Example:
                +        ```python
                +        streamer = client.chat_stream(
                +            channel="C0123456789",
                +            thread_ts="1700000001.123456",
                +            recipient_team_id="T0123456789",
                +            recipient_user_id="U0123456789",
                +        )
                +        streamer.append(markdown_text="**hello wo")
                +        streamer.append(markdown_text="rld!**")
                +        streamer.stop()
                +        ```
                +    """
                +    if self._state == "completed":
                +        raise e.SlackRequestError(f"Cannot append to stream: stream state is {self._state}")
                +    if kwargs.get("token"):
                +        self._token = kwargs.pop("token")
                +    self._buffer += markdown_text
                +    if len(self._buffer) >= self._buffer_size:
                +        return await self._flush_buffer(**kwargs)
                +    details = {
                +        "buffer_length": len(self._buffer),
                +        "buffer_size": self._buffer_size,
                +        "channel": self._stream_args.get("channel"),
                +        "recipient_team_id": self._stream_args.get("recipient_team_id"),
                +        "recipient_user_id": self._stream_args.get("recipient_user_id"),
                +        "thread_ts": self._stream_args.get("thread_ts"),
                +    }
                +    self._logger.debug(f"ChatStream appended to buffer: {json.dumps(details)}")
                +    return None
                +
                +

                Append to the stream.

                +

                The "append" method appends to the chat stream being used. This method can be called multiple times. After the stream +is stopped this method cannot be called.

                +

                Args

                +
                +
                markdown_text
                +
                Accepts message text formatted in markdown. Limit this field to 12,000 characters. This text is +what will be appended to the message received so far.
                +
                **kwargs
                +
                Additional arguments passed to the underlying API calls.
                +
                +

                Returns

                +

                AsyncSlackResponse if the buffer was flushed, None if buffering.

                +

                Raises

                +
                +
                SlackRequestError
                +
                If the stream is already completed.
                +
                +

                Example

                +
                streamer = client.chat_stream(
                +    channel="C0123456789",
                +    thread_ts="1700000001.123456",
                +    recipient_team_id="T0123456789",
                +    recipient_user_id="U0123456789",
                +)
                +streamer.append(markdown_text="**hello wo")
                +streamer.append(markdown_text="rld!**")
                +streamer.stop()
                +
                +
                +
                +async def stop(self,
                *,
                markdown_text: str | None = None,
                blocks: str | Sequence[Dict | Block] | None = None,
                metadata: Dict | Metadata | None = None,
                **kwargs) ‑> AsyncSlackResponse
                +
                +
                +
                + +Expand source code + +
                async def stop(
                +    self,
                +    *,
                +    markdown_text: Optional[str] = None,
                +    blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None,
                +    metadata: Optional[Union[Dict, Metadata]] = None,
                +    **kwargs,
                +) -> AsyncSlackResponse:
                +    """Stop the stream and finalize the message.
                +
                +    Args:
                +        blocks: A list of blocks that will be rendered at the bottom of the finalized message.
                +        markdown_text: Accepts message text formatted in markdown. Limit this field to 12,000 characters. This text is
                +          what will be appended to the message received so far.
                +        metadata: JSON object with event_type and event_payload fields, presented as a URL-encoded string. Metadata you
                +          post to Slack is accessible to any app or user who is a member of that workspace.
                +        **kwargs: Additional arguments passed to the underlying API calls.
                +
                +    Returns:
                +        AsyncSlackResponse from the chat.stopStream API call.
                +
                +    Raises:
                +        SlackRequestError: If the stream is already completed.
                +
                +    Example:
                +        ```python
                +        streamer = client.chat_stream(
                +            channel="C0123456789",
                +            thread_ts="1700000001.123456",
                +            recipient_team_id="T0123456789",
                +            recipient_user_id="U0123456789",
                +        )
                +        streamer.append(markdown_text="**hello wo")
                +        streamer.append(markdown_text="rld!**")
                +        streamer.stop()
                +        ```
                +    """
                +    if self._state == "completed":
                +        raise e.SlackRequestError(f"Cannot stop stream: stream state is {self._state}")
                +    if kwargs.get("token"):
                +        self._token = kwargs.pop("token")
                +    if markdown_text:
                +        self._buffer += markdown_text
                +    if not self._stream_ts:
                +        response = await self._client.chat_startStream(
                +            **self._stream_args,
                +            token=self._token,
                +        )
                +        if not response.get("ts"):
                +            raise e.SlackRequestError("Failed to stop stream: stream not started")
                +        self._stream_ts = str(response["ts"])
                +        self._state = "in_progress"
                +    response = await self._client.chat_stopStream(
                +        token=self._token,
                +        channel=self._stream_args["channel"],
                +        ts=self._stream_ts,
                +        blocks=blocks,
                +        markdown_text=self._buffer,
                +        metadata=metadata,
                +        **kwargs,
                +    )
                +    self._state = "completed"
                +    return response
                +
                +

                Stop the stream and finalize the message.

                +

                Args

                +
                +
                blocks
                +
                A list of blocks that will be rendered at the bottom of the finalized message.
                +
                markdown_text
                +
                Accepts message text formatted in markdown. Limit this field to 12,000 characters. This text is +what will be appended to the message received so far.
                +
                metadata
                +
                JSON object with event_type and event_payload fields, presented as a URL-encoded string. Metadata you +post to Slack is accessible to any app or user who is a member of that workspace.
                +
                **kwargs
                +
                Additional arguments passed to the underlying API calls.
                +
                +

                Returns

                +

                AsyncSlackResponse from the chat.stopStream API call.

                +

                Raises

                +
                +
                SlackRequestError
                +
                If the stream is already completed.
                +
                +

                Example

                +
                streamer = client.chat_stream(
                +    channel="C0123456789",
                +    thread_ts="1700000001.123456",
                +    recipient_team_id="T0123456789",
                +    recipient_user_id="U0123456789",
                +)
                +streamer.append(markdown_text="**hello wo")
                +streamer.append(markdown_text="rld!**")
                +streamer.stop()
                +
                +
                +
                +
                +
                +
                +
                + +
                + + + diff --git a/docs/reference/web/async_client.html b/docs/reference/web/async_client.html index 9d895fea8..7a46cf18c 100644 --- a/docs/reference/web/async_client.html +++ b/docs/reference/web/async_client.html @@ -2952,6 +2952,69 @@

                Classes

                kwargs = _remove_none_values(kwargs) return await self.api_call("chat.stopStream", json=kwargs) + async def chat_stream( + self, + *, + buffer_size: int = 256, + channel: str, + thread_ts: str, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, + **kwargs, + ) -> AsyncChatStream: + """Stream markdown text into a conversation. + + This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, + the stream can be stopped with concluding arguments such as "blocks" for gathering feedback. + + The following methods are used: + + - chat.startStream: Starts a new streaming conversation. + [Reference](https://docs.slack.dev/reference/methods/chat.startStream). + - chat.appendStream: Appends text to an existing streaming conversation. + [Reference](https://docs.slack.dev/reference/methods/chat.appendStream). + - chat.stopStream: Stops a streaming conversation. + [Reference](https://docs.slack.dev/reference/methods/chat.stopStream). + + Args: + buffer_size: The length of markdown_text to buffer in-memory before calling a stream method. Increasing this + value decreases the number of method calls made for the same amount of text, which is useful to avoid rate + limits. Default: 256. + channel: An encoded ID that represents a channel, private group, or DM. + thread_ts: Provide another message's ts value to reply to. Streamed messages should always be replies to a user + request. + recipient_team_id: The encoded ID of the team the user receiving the streaming text belongs to. Required when + streaming to channels. + recipient_user_id: The encoded ID of the user to receive the streaming text. Required when streaming to channels. + **kwargs: Additional arguments passed to the underlying API calls. + + Returns: + ChatStream instance for managing the stream + + Example: + ```python + streamer = await client.chat_stream( + channel="C0123456789", + thread_ts="1700000001.123456", + recipient_team_id="T0123456789", + recipient_user_id="U0123456789", + ) + await streamer.append(markdown_text="**hello wo") + await streamer.append(markdown_text="rld!**") + await streamer.stop() + ``` + """ + return AsyncChatStream( + self, + logger=self._logger, + channel=channel, + thread_ts=thread_ts, + recipient_team_id=recipient_team_id, + recipient_user_id=recipient_user_id, + buffer_size=buffer_size, + **kwargs, + ) + async def chat_unfurl( self, *, @@ -10242,6 +10305,122 @@

                Methods

                Stops a streaming conversation. https://api.slack.com/methods/chat.stopStream

                +
                +async def chat_stream(self,
                *,
                buffer_size: int = 256,
                channel: str,
                thread_ts: str,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                **kwargs) ‑> AsyncChatStream
                +
                +
                +
                + +Expand source code + +
                async def chat_stream(
                +    self,
                +    *,
                +    buffer_size: int = 256,
                +    channel: str,
                +    thread_ts: str,
                +    recipient_team_id: Optional[str] = None,
                +    recipient_user_id: Optional[str] = None,
                +    **kwargs,
                +) -> AsyncChatStream:
                +    """Stream markdown text into a conversation.
                +
                +    This method starts a new chat stream in a coversation that can be appended to. After appending an entire message,
                +    the stream can be stopped with concluding arguments such as "blocks" for gathering feedback.
                +
                +    The following methods are used:
                +
                +    - chat.startStream: Starts a new streaming conversation.
                +      [Reference](https://docs.slack.dev/reference/methods/chat.startStream).
                +    - chat.appendStream: Appends text to an existing streaming conversation.
                +      [Reference](https://docs.slack.dev/reference/methods/chat.appendStream).
                +    - chat.stopStream: Stops a streaming conversation.
                +      [Reference](https://docs.slack.dev/reference/methods/chat.stopStream).
                +
                +    Args:
                +        buffer_size: The length of markdown_text to buffer in-memory before calling a stream method. Increasing this
                +          value decreases the number of method calls made for the same amount of text, which is useful to avoid rate
                +          limits. Default: 256.
                +        channel: An encoded ID that represents a channel, private group, or DM.
                +        thread_ts: Provide another message's ts value to reply to. Streamed messages should always be replies to a user
                +          request.
                +        recipient_team_id: The encoded ID of the team the user receiving the streaming text belongs to. Required when
                +          streaming to channels.
                +        recipient_user_id: The encoded ID of the user to receive the streaming text. Required when streaming to channels.
                +        **kwargs: Additional arguments passed to the underlying API calls.
                +
                +    Returns:
                +        ChatStream instance for managing the stream
                +
                +    Example:
                +        ```python
                +        streamer = await client.chat_stream(
                +            channel="C0123456789",
                +            thread_ts="1700000001.123456",
                +            recipient_team_id="T0123456789",
                +            recipient_user_id="U0123456789",
                +        )
                +        await streamer.append(markdown_text="**hello wo")
                +        await streamer.append(markdown_text="rld!**")
                +        await streamer.stop()
                +        ```
                +    """
                +    return AsyncChatStream(
                +        self,
                +        logger=self._logger,
                +        channel=channel,
                +        thread_ts=thread_ts,
                +        recipient_team_id=recipient_team_id,
                +        recipient_user_id=recipient_user_id,
                +        buffer_size=buffer_size,
                +        **kwargs,
                +    )
                +
                +

                Stream markdown text into a conversation.

                +

                This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, +the stream can be stopped with concluding arguments such as "blocks" for gathering feedback.

                +

                The following methods are used:

                +
                  +
                • chat.startStream: Starts a new streaming conversation. +Reference.
                • +
                • chat.appendStream: Appends text to an existing streaming conversation. +Reference.
                • +
                • chat.stopStream: Stops a streaming conversation. +Reference.
                • +
                +

                Args

                +
                +
                buffer_size
                +
                The length of markdown_text to buffer in-memory before calling a stream method. Increasing this +value decreases the number of method calls made for the same amount of text, which is useful to avoid rate +limits. Default: 256.
                +
                channel
                +
                An encoded ID that represents a channel, private group, or DM.
                +
                thread_ts
                +
                Provide another message's ts value to reply to. Streamed messages should always be replies to a user +request.
                +
                recipient_team_id
                +
                The encoded ID of the team the user receiving the streaming text belongs to. Required when +streaming to channels.
                +
                recipient_user_id
                +
                The encoded ID of the user to receive the streaming text. Required when streaming to channels.
                +
                **kwargs
                +
                Additional arguments passed to the underlying API calls.
                +
                +

                Returns

                +

                ChatStream instance for managing the stream

                +

                Example

                +
                streamer = await client.chat_stream(
                +    channel="C0123456789",
                +    thread_ts="1700000001.123456",
                +    recipient_team_id="T0123456789",
                +    recipient_user_id="U0123456789",
                +)
                +await streamer.append(markdown_text="**hello wo")
                +await streamer.append(markdown_text="rld!**")
                +await streamer.stop()
                +
                +
                async def chat_unfurl(self,
                *,
                channel: str | None = None,
                ts: str | None = None,
                source: str | None = None,
                unfurl_id: str | None = None,
                unfurls: Dict[str, Dict] | None = None,
                user_auth_blocks: str | Sequence[Dict | Block] | None = None,
                user_auth_message: str | None = None,
                user_auth_required: bool | None = None,
                user_auth_url: str | None = None,
                **kwargs) ‑> AsyncSlackResponse
                @@ -14759,6 +14938,7 @@

                chat_scheduledMessages_list
              • chat_startStream
              • chat_stopStream
              • +
              • chat_stream
              • chat_unfurl
              • chat_update
              • conversations_acceptSharedInvite
              • diff --git a/docs/reference/web/chat_stream.html b/docs/reference/web/chat_stream.html new file mode 100644 index 000000000..94d96e5eb --- /dev/null +++ b/docs/reference/web/chat_stream.html @@ -0,0 +1,506 @@ + + + + + + +slack_sdk.web.chat_stream API documentation + + + + + + + + + + + +
                +
                +
                +

                Module slack_sdk.web.chat_stream

                +
                +
                +
                +
                +
                +
                +
                +
                +
                +
                +

                Classes

                +
                +
                +class ChatStream +(client: WebClient,
                *,
                channel: str,
                logger: logging.Logger,
                thread_ts: str,
                buffer_size: int,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                **kwargs)
                +
                +
                +
                + +Expand source code + +
                class ChatStream:
                +    """A helper class for streaming markdown text into a conversation using the chat streaming APIs.
                +
                +    This class provides a convenient interface for the chat.startStream, chat.appendStream, and chat.stopStream API
                +    methods, with automatic buffering and state management.
                +    """
                +
                +    def __init__(
                +        self,
                +        client: "WebClient",
                +        *,
                +        channel: str,
                +        logger: logging.Logger,
                +        thread_ts: str,
                +        buffer_size: int,
                +        recipient_team_id: Optional[str] = None,
                +        recipient_user_id: Optional[str] = None,
                +        **kwargs,
                +    ):
                +        """Initialize a new ChatStream instance.
                +
                +        The __init__ method creates a unique ChatStream instance that keeps track of one chat stream.
                +
                +        Args:
                +            client: The WebClient instance to use for API calls.
                +            channel: An encoded ID that represents a channel, private group, or DM.
                +            logger: A logging channel for outputs.
                +            thread_ts: Provide another message's ts value to reply to. Streamed messages should always be replies to a user
                +              request.
                +            recipient_team_id: The encoded ID of the team the user receiving the streaming text belongs to. Required when
                +              streaming to channels.
                +            recipient_user_id: The encoded ID of the user to receive the streaming text. Required when streaming to channels.
                +            buffer_size: The length of markdown_text to buffer in-memory before calling a method. Increasing this value
                +              decreases the number of method calls made for the same amount of text, which is useful to avoid rate limits.
                +            **kwargs: Additional arguments passed to the underlying API calls.
                +        """
                +        self._client = client
                +        self._logger = logger
                +        self._token: Optional[str] = kwargs.pop("token", None)
                +        self._stream_args = {
                +            "channel": channel,
                +            "thread_ts": thread_ts,
                +            "recipient_team_id": recipient_team_id,
                +            "recipient_user_id": recipient_user_id,
                +            **kwargs,
                +        }
                +        self._buffer = ""
                +        self._state = "starting"
                +        self._stream_ts: Optional[str] = None
                +        self._buffer_size = buffer_size
                +
                +    def append(
                +        self,
                +        *,
                +        markdown_text: str,
                +        **kwargs,
                +    ) -> Optional[SlackResponse]:
                +        """Append to the stream.
                +
                +        The "append" method appends to the chat stream being used. This method can be called multiple times. After the stream
                +        is stopped this method cannot be called.
                +
                +        Args:
                +            markdown_text: Accepts message text formatted in markdown. Limit this field to 12,000 characters. This text is
                +              what will be appended to the message received so far.
                +            **kwargs: Additional arguments passed to the underlying API calls.
                +
                +        Returns:
                +            SlackResponse if the buffer was flushed, None if buffering.
                +
                +        Raises:
                +            SlackRequestError: If the stream is already completed.
                +
                +        Example:
                +            ```python
                +            streamer = client.chat_stream(
                +                channel="C0123456789",
                +                thread_ts="1700000001.123456",
                +                recipient_team_id="T0123456789",
                +                recipient_user_id="U0123456789",
                +            )
                +            streamer.append(markdown_text="**hello wo")
                +            streamer.append(markdown_text="rld!**")
                +            streamer.stop()
                +            ```
                +        """
                +        if self._state == "completed":
                +            raise e.SlackRequestError(f"Cannot append to stream: stream state is {self._state}")
                +        if kwargs.get("token"):
                +            self._token = kwargs.pop("token")
                +        self._buffer += markdown_text
                +        if len(self._buffer) >= self._buffer_size:
                +            return self._flush_buffer(**kwargs)
                +        details = {
                +            "buffer_length": len(self._buffer),
                +            "buffer_size": self._buffer_size,
                +            "channel": self._stream_args.get("channel"),
                +            "recipient_team_id": self._stream_args.get("recipient_team_id"),
                +            "recipient_user_id": self._stream_args.get("recipient_user_id"),
                +            "thread_ts": self._stream_args.get("thread_ts"),
                +        }
                +        self._logger.debug(f"ChatStream appended to buffer: {json.dumps(details)}")
                +        return None
                +
                +    def stop(
                +        self,
                +        *,
                +        markdown_text: Optional[str] = None,
                +        blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None,
                +        metadata: Optional[Union[Dict, Metadata]] = None,
                +        **kwargs,
                +    ) -> SlackResponse:
                +        """Stop the stream and finalize the message.
                +
                +        Args:
                +            blocks: A list of blocks that will be rendered at the bottom of the finalized message.
                +            markdown_text: Accepts message text formatted in markdown. Limit this field to 12,000 characters. This text is
                +              what will be appended to the message received so far.
                +            metadata: JSON object with event_type and event_payload fields, presented as a URL-encoded string. Metadata you
                +              post to Slack is accessible to any app or user who is a member of that workspace.
                +            **kwargs: Additional arguments passed to the underlying API calls.
                +
                +        Returns:
                +            SlackResponse from the chat.stopStream API call.
                +
                +        Raises:
                +            SlackRequestError: If the stream is already completed.
                +
                +        Example:
                +            ```python
                +            streamer = client.chat_stream(
                +                channel="C0123456789",
                +                thread_ts="1700000001.123456",
                +                recipient_team_id="T0123456789",
                +                recipient_user_id="U0123456789",
                +            )
                +            streamer.append(markdown_text="**hello wo")
                +            streamer.append(markdown_text="rld!**")
                +            streamer.stop()
                +            ```
                +        """
                +        if self._state == "completed":
                +            raise e.SlackRequestError(f"Cannot stop stream: stream state is {self._state}")
                +        if kwargs.get("token"):
                +            self._token = kwargs.pop("token")
                +        if markdown_text:
                +            self._buffer += markdown_text
                +        if not self._stream_ts:
                +            response = self._client.chat_startStream(
                +                **self._stream_args,
                +                token=self._token,
                +            )
                +            if not response.get("ts"):
                +                raise e.SlackRequestError("Failed to stop stream: stream not started")
                +            self._stream_ts = str(response["ts"])
                +            self._state = "in_progress"
                +        response = self._client.chat_stopStream(
                +            token=self._token,
                +            channel=self._stream_args["channel"],
                +            ts=self._stream_ts,
                +            blocks=blocks,
                +            markdown_text=self._buffer,
                +            metadata=metadata,
                +            **kwargs,
                +        )
                +        self._state = "completed"
                +        return response
                +
                +    def _flush_buffer(self, **kwargs) -> SlackResponse:
                +        """Flush the internal buffer by making appropriate API calls."""
                +        if not self._stream_ts:
                +            response = self._client.chat_startStream(
                +                **self._stream_args,
                +                token=self._token,
                +                **kwargs,
                +                markdown_text=self._buffer,
                +            )
                +            self._stream_ts = response.get("ts")
                +            self._state = "in_progress"
                +        else:
                +            response = self._client.chat_appendStream(
                +                token=self._token,
                +                channel=self._stream_args["channel"],
                +                ts=self._stream_ts,
                +                **kwargs,
                +                markdown_text=self._buffer,
                +            )
                +        self._buffer = ""
                +        return response
                +
                +

                A helper class for streaming markdown text into a conversation using the chat streaming APIs.

                +

                This class provides a convenient interface for the chat.startStream, chat.appendStream, and chat.stopStream API +methods, with automatic buffering and state management.

                +

                Initialize a new ChatStream instance.

                +

                The init method creates a unique ChatStream instance that keeps track of one chat stream.

                +

                Args

                +
                +
                client
                +
                The WebClient instance to use for API calls.
                +
                channel
                +
                An encoded ID that represents a channel, private group, or DM.
                +
                logger
                +
                A logging channel for outputs.
                +
                thread_ts
                +
                Provide another message's ts value to reply to. Streamed messages should always be replies to a user +request.
                +
                recipient_team_id
                +
                The encoded ID of the team the user receiving the streaming text belongs to. Required when +streaming to channels.
                +
                recipient_user_id
                +
                The encoded ID of the user to receive the streaming text. Required when streaming to channels.
                +
                buffer_size
                +
                The length of markdown_text to buffer in-memory before calling a method. Increasing this value +decreases the number of method calls made for the same amount of text, which is useful to avoid rate limits.
                +
                **kwargs
                +
                Additional arguments passed to the underlying API calls.
                +
                +

                Methods

                +
                +
                +def append(self, *, markdown_text: str, **kwargs) ‑> SlackResponse | None +
                +
                +
                + +Expand source code + +
                def append(
                +    self,
                +    *,
                +    markdown_text: str,
                +    **kwargs,
                +) -> Optional[SlackResponse]:
                +    """Append to the stream.
                +
                +    The "append" method appends to the chat stream being used. This method can be called multiple times. After the stream
                +    is stopped this method cannot be called.
                +
                +    Args:
                +        markdown_text: Accepts message text formatted in markdown. Limit this field to 12,000 characters. This text is
                +          what will be appended to the message received so far.
                +        **kwargs: Additional arguments passed to the underlying API calls.
                +
                +    Returns:
                +        SlackResponse if the buffer was flushed, None if buffering.
                +
                +    Raises:
                +        SlackRequestError: If the stream is already completed.
                +
                +    Example:
                +        ```python
                +        streamer = client.chat_stream(
                +            channel="C0123456789",
                +            thread_ts="1700000001.123456",
                +            recipient_team_id="T0123456789",
                +            recipient_user_id="U0123456789",
                +        )
                +        streamer.append(markdown_text="**hello wo")
                +        streamer.append(markdown_text="rld!**")
                +        streamer.stop()
                +        ```
                +    """
                +    if self._state == "completed":
                +        raise e.SlackRequestError(f"Cannot append to stream: stream state is {self._state}")
                +    if kwargs.get("token"):
                +        self._token = kwargs.pop("token")
                +    self._buffer += markdown_text
                +    if len(self._buffer) >= self._buffer_size:
                +        return self._flush_buffer(**kwargs)
                +    details = {
                +        "buffer_length": len(self._buffer),
                +        "buffer_size": self._buffer_size,
                +        "channel": self._stream_args.get("channel"),
                +        "recipient_team_id": self._stream_args.get("recipient_team_id"),
                +        "recipient_user_id": self._stream_args.get("recipient_user_id"),
                +        "thread_ts": self._stream_args.get("thread_ts"),
                +    }
                +    self._logger.debug(f"ChatStream appended to buffer: {json.dumps(details)}")
                +    return None
                +
                +

                Append to the stream.

                +

                The "append" method appends to the chat stream being used. This method can be called multiple times. After the stream +is stopped this method cannot be called.

                +

                Args

                +
                +
                markdown_text
                +
                Accepts message text formatted in markdown. Limit this field to 12,000 characters. This text is +what will be appended to the message received so far.
                +
                **kwargs
                +
                Additional arguments passed to the underlying API calls.
                +
                +

                Returns

                +

                SlackResponse if the buffer was flushed, None if buffering.

                +

                Raises

                +
                +
                SlackRequestError
                +
                If the stream is already completed.
                +
                +

                Example

                +
                streamer = client.chat_stream(
                +    channel="C0123456789",
                +    thread_ts="1700000001.123456",
                +    recipient_team_id="T0123456789",
                +    recipient_user_id="U0123456789",
                +)
                +streamer.append(markdown_text="**hello wo")
                +streamer.append(markdown_text="rld!**")
                +streamer.stop()
                +
                +
                +
                +def stop(self,
                *,
                markdown_text: str | None = None,
                blocks: str | Sequence[Dict | Block] | None = None,
                metadata: Dict | Metadata | None = None,
                **kwargs) ‑> SlackResponse
                +
                +
                +
                + +Expand source code + +
                def stop(
                +    self,
                +    *,
                +    markdown_text: Optional[str] = None,
                +    blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None,
                +    metadata: Optional[Union[Dict, Metadata]] = None,
                +    **kwargs,
                +) -> SlackResponse:
                +    """Stop the stream and finalize the message.
                +
                +    Args:
                +        blocks: A list of blocks that will be rendered at the bottom of the finalized message.
                +        markdown_text: Accepts message text formatted in markdown. Limit this field to 12,000 characters. This text is
                +          what will be appended to the message received so far.
                +        metadata: JSON object with event_type and event_payload fields, presented as a URL-encoded string. Metadata you
                +          post to Slack is accessible to any app or user who is a member of that workspace.
                +        **kwargs: Additional arguments passed to the underlying API calls.
                +
                +    Returns:
                +        SlackResponse from the chat.stopStream API call.
                +
                +    Raises:
                +        SlackRequestError: If the stream is already completed.
                +
                +    Example:
                +        ```python
                +        streamer = client.chat_stream(
                +            channel="C0123456789",
                +            thread_ts="1700000001.123456",
                +            recipient_team_id="T0123456789",
                +            recipient_user_id="U0123456789",
                +        )
                +        streamer.append(markdown_text="**hello wo")
                +        streamer.append(markdown_text="rld!**")
                +        streamer.stop()
                +        ```
                +    """
                +    if self._state == "completed":
                +        raise e.SlackRequestError(f"Cannot stop stream: stream state is {self._state}")
                +    if kwargs.get("token"):
                +        self._token = kwargs.pop("token")
                +    if markdown_text:
                +        self._buffer += markdown_text
                +    if not self._stream_ts:
                +        response = self._client.chat_startStream(
                +            **self._stream_args,
                +            token=self._token,
                +        )
                +        if not response.get("ts"):
                +            raise e.SlackRequestError("Failed to stop stream: stream not started")
                +        self._stream_ts = str(response["ts"])
                +        self._state = "in_progress"
                +    response = self._client.chat_stopStream(
                +        token=self._token,
                +        channel=self._stream_args["channel"],
                +        ts=self._stream_ts,
                +        blocks=blocks,
                +        markdown_text=self._buffer,
                +        metadata=metadata,
                +        **kwargs,
                +    )
                +    self._state = "completed"
                +    return response
                +
                +

                Stop the stream and finalize the message.

                +

                Args

                +
                +
                blocks
                +
                A list of blocks that will be rendered at the bottom of the finalized message.
                +
                markdown_text
                +
                Accepts message text formatted in markdown. Limit this field to 12,000 characters. This text is +what will be appended to the message received so far.
                +
                metadata
                +
                JSON object with event_type and event_payload fields, presented as a URL-encoded string. Metadata you +post to Slack is accessible to any app or user who is a member of that workspace.
                +
                **kwargs
                +
                Additional arguments passed to the underlying API calls.
                +
                +

                Returns

                +

                SlackResponse from the chat.stopStream API call.

                +

                Raises

                +
                +
                SlackRequestError
                +
                If the stream is already completed.
                +
                +

                Example

                +
                streamer = client.chat_stream(
                +    channel="C0123456789",
                +    thread_ts="1700000001.123456",
                +    recipient_team_id="T0123456789",
                +    recipient_user_id="U0123456789",
                +)
                +streamer.append(markdown_text="**hello wo")
                +streamer.append(markdown_text="rld!**")
                +streamer.stop()
                +
                +
                +
                +
                +
                +
                +
                + +
                + + + diff --git a/docs/reference/web/client.html b/docs/reference/web/client.html index e6704424c..162df0964 100644 --- a/docs/reference/web/client.html +++ b/docs/reference/web/client.html @@ -2952,6 +2952,69 @@

                Classes

                kwargs = _remove_none_values(kwargs) return self.api_call("chat.stopStream", json=kwargs) + def chat_stream( + self, + *, + buffer_size: int = 256, + channel: str, + thread_ts: str, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, + **kwargs, + ) -> ChatStream: + """Stream markdown text into a conversation. + + This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, + the stream can be stopped with concluding arguments such as "blocks" for gathering feedback. + + The following methods are used: + + - chat.startStream: Starts a new streaming conversation. + [Reference](https://docs.slack.dev/reference/methods/chat.startStream). + - chat.appendStream: Appends text to an existing streaming conversation. + [Reference](https://docs.slack.dev/reference/methods/chat.appendStream). + - chat.stopStream: Stops a streaming conversation. + [Reference](https://docs.slack.dev/reference/methods/chat.stopStream). + + Args: + buffer_size: The length of markdown_text to buffer in-memory before calling a stream method. Increasing this + value decreases the number of method calls made for the same amount of text, which is useful to avoid rate + limits. Default: 256. + channel: An encoded ID that represents a channel, private group, or DM. + thread_ts: Provide another message's ts value to reply to. Streamed messages should always be replies to a user + request. + recipient_team_id: The encoded ID of the team the user receiving the streaming text belongs to. Required when + streaming to channels. + recipient_user_id: The encoded ID of the user to receive the streaming text. Required when streaming to channels. + **kwargs: Additional arguments passed to the underlying API calls. + + Returns: + ChatStream instance for managing the stream + + Example: + ```python + streamer = client.chat_stream( + channel="C0123456789", + thread_ts="1700000001.123456", + recipient_team_id="T0123456789", + recipient_user_id="U0123456789", + ) + streamer.append(markdown_text="**hello wo") + streamer.append(markdown_text="rld!**") + streamer.stop() + ``` + """ + return ChatStream( + self, + logger=self._logger, + channel=channel, + thread_ts=thread_ts, + recipient_team_id=recipient_team_id, + recipient_user_id=recipient_user_id, + buffer_size=buffer_size, + **kwargs, + ) + def chat_unfurl( self, *, @@ -10242,6 +10305,122 @@

                Methods

                Stops a streaming conversation. https://api.slack.com/methods/chat.stopStream

                +
                +def chat_stream(self,
                *,
                buffer_size: int = 256,
                channel: str,
                thread_ts: str,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                **kwargs) ‑> ChatStream
                +
                +
                +
                + +Expand source code + +
                def chat_stream(
                +    self,
                +    *,
                +    buffer_size: int = 256,
                +    channel: str,
                +    thread_ts: str,
                +    recipient_team_id: Optional[str] = None,
                +    recipient_user_id: Optional[str] = None,
                +    **kwargs,
                +) -> ChatStream:
                +    """Stream markdown text into a conversation.
                +
                +    This method starts a new chat stream in a coversation that can be appended to. After appending an entire message,
                +    the stream can be stopped with concluding arguments such as "blocks" for gathering feedback.
                +
                +    The following methods are used:
                +
                +    - chat.startStream: Starts a new streaming conversation.
                +      [Reference](https://docs.slack.dev/reference/methods/chat.startStream).
                +    - chat.appendStream: Appends text to an existing streaming conversation.
                +      [Reference](https://docs.slack.dev/reference/methods/chat.appendStream).
                +    - chat.stopStream: Stops a streaming conversation.
                +      [Reference](https://docs.slack.dev/reference/methods/chat.stopStream).
                +
                +    Args:
                +        buffer_size: The length of markdown_text to buffer in-memory before calling a stream method. Increasing this
                +          value decreases the number of method calls made for the same amount of text, which is useful to avoid rate
                +          limits. Default: 256.
                +        channel: An encoded ID that represents a channel, private group, or DM.
                +        thread_ts: Provide another message's ts value to reply to. Streamed messages should always be replies to a user
                +          request.
                +        recipient_team_id: The encoded ID of the team the user receiving the streaming text belongs to. Required when
                +          streaming to channels.
                +        recipient_user_id: The encoded ID of the user to receive the streaming text. Required when streaming to channels.
                +        **kwargs: Additional arguments passed to the underlying API calls.
                +
                +    Returns:
                +        ChatStream instance for managing the stream
                +
                +    Example:
                +        ```python
                +        streamer = client.chat_stream(
                +            channel="C0123456789",
                +            thread_ts="1700000001.123456",
                +            recipient_team_id="T0123456789",
                +            recipient_user_id="U0123456789",
                +        )
                +        streamer.append(markdown_text="**hello wo")
                +        streamer.append(markdown_text="rld!**")
                +        streamer.stop()
                +        ```
                +    """
                +    return ChatStream(
                +        self,
                +        logger=self._logger,
                +        channel=channel,
                +        thread_ts=thread_ts,
                +        recipient_team_id=recipient_team_id,
                +        recipient_user_id=recipient_user_id,
                +        buffer_size=buffer_size,
                +        **kwargs,
                +    )
                +
                +

                Stream markdown text into a conversation.

                +

                This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, +the stream can be stopped with concluding arguments such as "blocks" for gathering feedback.

                +

                The following methods are used:

                +
                  +
                • chat.startStream: Starts a new streaming conversation. +Reference.
                • +
                • chat.appendStream: Appends text to an existing streaming conversation. +Reference.
                • +
                • chat.stopStream: Stops a streaming conversation. +Reference.
                • +
                +

                Args

                +
                +
                buffer_size
                +
                The length of markdown_text to buffer in-memory before calling a stream method. Increasing this +value decreases the number of method calls made for the same amount of text, which is useful to avoid rate +limits. Default: 256.
                +
                channel
                +
                An encoded ID that represents a channel, private group, or DM.
                +
                thread_ts
                +
                Provide another message's ts value to reply to. Streamed messages should always be replies to a user +request.
                +
                recipient_team_id
                +
                The encoded ID of the team the user receiving the streaming text belongs to. Required when +streaming to channels.
                +
                recipient_user_id
                +
                The encoded ID of the user to receive the streaming text. Required when streaming to channels.
                +
                **kwargs
                +
                Additional arguments passed to the underlying API calls.
                +
                +

                Returns

                +

                ChatStream instance for managing the stream

                +

                Example

                +
                streamer = client.chat_stream(
                +    channel="C0123456789",
                +    thread_ts="1700000001.123456",
                +    recipient_team_id="T0123456789",
                +    recipient_user_id="U0123456789",
                +)
                +streamer.append(markdown_text="**hello wo")
                +streamer.append(markdown_text="rld!**")
                +streamer.stop()
                +
                +
                def chat_unfurl(self,
                *,
                channel: str | None = None,
                ts: str | None = None,
                source: str | None = None,
                unfurl_id: str | None = None,
                unfurls: Dict[str, Dict] | None = None,
                user_auth_blocks: str | Sequence[Dict | Block] | None = None,
                user_auth_message: str | None = None,
                user_auth_required: bool | None = None,
                user_auth_url: str | None = None,
                **kwargs) ‑> SlackResponse
                @@ -14758,6 +14937,7 @@

                chat_scheduledMessages_list
              • chat_startStream
              • chat_stopStream
              • +
              • chat_stream
              • chat_unfurl
              • chat_update
              • conversations_acceptSharedInvite
              • diff --git a/docs/reference/web/index.html b/docs/reference/web/index.html index 2e9c01af9..c2df7f11f 100644 --- a/docs/reference/web/index.html +++ b/docs/reference/web/index.html @@ -47,6 +47,10 @@

                Sub-modules

                +
                slack_sdk.web.async_chat_stream
                +
                +
                +
                slack_sdk.web.async_client

                A Python module for interacting with Slack's Web API.

                @@ -63,6 +67,10 @@

                Sub-modules

                A Python module for interacting with Slack's Web API.

                +
                slack_sdk.web.chat_stream
                +
                +
                +
                slack_sdk.web.client

                A Python module for interacting with Slack's Web API.

                @@ -3313,6 +3321,69 @@

                Raises

                kwargs = _remove_none_values(kwargs) return self.api_call("chat.stopStream", json=kwargs) + def chat_stream( + self, + *, + buffer_size: int = 256, + channel: str, + thread_ts: str, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, + **kwargs, + ) -> ChatStream: + """Stream markdown text into a conversation. + + This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, + the stream can be stopped with concluding arguments such as "blocks" for gathering feedback. + + The following methods are used: + + - chat.startStream: Starts a new streaming conversation. + [Reference](https://docs.slack.dev/reference/methods/chat.startStream). + - chat.appendStream: Appends text to an existing streaming conversation. + [Reference](https://docs.slack.dev/reference/methods/chat.appendStream). + - chat.stopStream: Stops a streaming conversation. + [Reference](https://docs.slack.dev/reference/methods/chat.stopStream). + + Args: + buffer_size: The length of markdown_text to buffer in-memory before calling a stream method. Increasing this + value decreases the number of method calls made for the same amount of text, which is useful to avoid rate + limits. Default: 256. + channel: An encoded ID that represents a channel, private group, or DM. + thread_ts: Provide another message's ts value to reply to. Streamed messages should always be replies to a user + request. + recipient_team_id: The encoded ID of the team the user receiving the streaming text belongs to. Required when + streaming to channels. + recipient_user_id: The encoded ID of the user to receive the streaming text. Required when streaming to channels. + **kwargs: Additional arguments passed to the underlying API calls. + + Returns: + ChatStream instance for managing the stream + + Example: + ```python + streamer = client.chat_stream( + channel="C0123456789", + thread_ts="1700000001.123456", + recipient_team_id="T0123456789", + recipient_user_id="U0123456789", + ) + streamer.append(markdown_text="**hello wo") + streamer.append(markdown_text="rld!**") + streamer.stop() + ``` + """ + return ChatStream( + self, + logger=self._logger, + channel=channel, + thread_ts=thread_ts, + recipient_team_id=recipient_team_id, + recipient_user_id=recipient_user_id, + buffer_size=buffer_size, + **kwargs, + ) + def chat_unfurl( self, *, @@ -10603,6 +10674,122 @@

                Methods

                Stops a streaming conversation. https://api.slack.com/methods/chat.stopStream

                +
                +def chat_stream(self,
                *,
                buffer_size: int = 256,
                channel: str,
                thread_ts: str,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                **kwargs) ‑> ChatStream
                +
                +
                +
                + +Expand source code + +
                def chat_stream(
                +    self,
                +    *,
                +    buffer_size: int = 256,
                +    channel: str,
                +    thread_ts: str,
                +    recipient_team_id: Optional[str] = None,
                +    recipient_user_id: Optional[str] = None,
                +    **kwargs,
                +) -> ChatStream:
                +    """Stream markdown text into a conversation.
                +
                +    This method starts a new chat stream in a coversation that can be appended to. After appending an entire message,
                +    the stream can be stopped with concluding arguments such as "blocks" for gathering feedback.
                +
                +    The following methods are used:
                +
                +    - chat.startStream: Starts a new streaming conversation.
                +      [Reference](https://docs.slack.dev/reference/methods/chat.startStream).
                +    - chat.appendStream: Appends text to an existing streaming conversation.
                +      [Reference](https://docs.slack.dev/reference/methods/chat.appendStream).
                +    - chat.stopStream: Stops a streaming conversation.
                +      [Reference](https://docs.slack.dev/reference/methods/chat.stopStream).
                +
                +    Args:
                +        buffer_size: The length of markdown_text to buffer in-memory before calling a stream method. Increasing this
                +          value decreases the number of method calls made for the same amount of text, which is useful to avoid rate
                +          limits. Default: 256.
                +        channel: An encoded ID that represents a channel, private group, or DM.
                +        thread_ts: Provide another message's ts value to reply to. Streamed messages should always be replies to a user
                +          request.
                +        recipient_team_id: The encoded ID of the team the user receiving the streaming text belongs to. Required when
                +          streaming to channels.
                +        recipient_user_id: The encoded ID of the user to receive the streaming text. Required when streaming to channels.
                +        **kwargs: Additional arguments passed to the underlying API calls.
                +
                +    Returns:
                +        ChatStream instance for managing the stream
                +
                +    Example:
                +        ```python
                +        streamer = client.chat_stream(
                +            channel="C0123456789",
                +            thread_ts="1700000001.123456",
                +            recipient_team_id="T0123456789",
                +            recipient_user_id="U0123456789",
                +        )
                +        streamer.append(markdown_text="**hello wo")
                +        streamer.append(markdown_text="rld!**")
                +        streamer.stop()
                +        ```
                +    """
                +    return ChatStream(
                +        self,
                +        logger=self._logger,
                +        channel=channel,
                +        thread_ts=thread_ts,
                +        recipient_team_id=recipient_team_id,
                +        recipient_user_id=recipient_user_id,
                +        buffer_size=buffer_size,
                +        **kwargs,
                +    )
                +
                +

                Stream markdown text into a conversation.

                +

                This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, +the stream can be stopped with concluding arguments such as "blocks" for gathering feedback.

                +

                The following methods are used:

                +
                  +
                • chat.startStream: Starts a new streaming conversation. +Reference.
                • +
                • chat.appendStream: Appends text to an existing streaming conversation. +Reference.
                • +
                • chat.stopStream: Stops a streaming conversation. +Reference.
                • +
                +

                Args

                +
                +
                buffer_size
                +
                The length of markdown_text to buffer in-memory before calling a stream method. Increasing this +value decreases the number of method calls made for the same amount of text, which is useful to avoid rate +limits. Default: 256.
                +
                channel
                +
                An encoded ID that represents a channel, private group, or DM.
                +
                thread_ts
                +
                Provide another message's ts value to reply to. Streamed messages should always be replies to a user +request.
                +
                recipient_team_id
                +
                The encoded ID of the team the user receiving the streaming text belongs to. Required when +streaming to channels.
                +
                recipient_user_id
                +
                The encoded ID of the user to receive the streaming text. Required when streaming to channels.
                +
                **kwargs
                +
                Additional arguments passed to the underlying API calls.
                +
                +

                Returns

                +

                ChatStream instance for managing the stream

                +

                Example

                +
                streamer = client.chat_stream(
                +    channel="C0123456789",
                +    thread_ts="1700000001.123456",
                +    recipient_team_id="T0123456789",
                +    recipient_user_id="U0123456789",
                +)
                +streamer.append(markdown_text="**hello wo")
                +streamer.append(markdown_text="rld!**")
                +streamer.stop()
                +
                +
                def chat_unfurl(self,
                *,
                channel: str | None = None,
                ts: str | None = None,
                source: str | None = None,
                unfurl_id: str | None = None,
                unfurls: Dict[str, Dict] | None = None,
                user_auth_blocks: str | Sequence[Dict | Block] | None = None,
                user_auth_message: str | None = None,
                user_auth_required: bool | None = None,
                user_auth_url: str | None = None,
                **kwargs) ‑> SlackResponse
                @@ -14961,10 +15148,12 @@

                Inherited members

              • Sub-modules

                • slack_sdk.web.async_base_client
                • +
                • slack_sdk.web.async_chat_stream
                • slack_sdk.web.async_client
                • slack_sdk.web.async_internal_utils
                • slack_sdk.web.async_slack_response
                • slack_sdk.web.base_client
                • +
                • slack_sdk.web.chat_stream
                • slack_sdk.web.client
                • slack_sdk.web.deprecation
                • slack_sdk.web.file_upload_v2_result
                • @@ -15143,6 +15332,7 @@

                  Web
                • chat_scheduledMessages_list
                • chat_startStream
                • chat_stopStream
                • +
                • chat_stream
                • chat_unfurl
                • chat_update
                • conversations_acceptSharedInvite
                • diff --git a/scripts/codegen.py b/scripts/codegen.py index f58de8bd1..3633faf35 100644 --- a/scripts/codegen.py +++ b/scripts/codegen.py @@ -1,5 +1,5 @@ -import sys import argparse +import sys parser = argparse.ArgumentParser() parser.add_argument("-p", "--path", help="Path to the project source code.", type=str) @@ -35,7 +35,6 @@ "from .async_base_client import AsyncBaseClient, AsyncSlackResponse", async_source, ) - # from slack_sdk import WebClient async_source = re.sub( r"class WebClient\(BaseClient\):", "class AsyncWebClient(AsyncBaseClient):", @@ -47,6 +46,28 @@ async_source, ) async_source = re.sub(r"= WebClient\(", "= AsyncWebClient(", async_source) + async_source = re.sub( + "from slack_sdk.web.chat_stream import ChatStream", + "from slack_sdk.web.async_chat_stream import AsyncChatStream", + async_source, + ) + async_source = re.sub(r"ChatStream:", "AsyncChatStream:", async_source) + async_source = re.sub(r"ChatStream\(", "AsyncChatStream(", async_source) + async_source = re.sub( + r" client.chat_stream\(", + " await client.chat_stream(", + async_source, + ) + async_source = re.sub( + r" streamer.append\(", + " await streamer.append(", + async_source, + ) + async_source = re.sub( + r" streamer.stop\(", + " await streamer.stop(", + async_source, + ) async_source = re.sub( r" self.files_getUploadURLExternal\(", " await self.files_getUploadURLExternal(", @@ -98,5 +119,35 @@ legacy_source, ) legacy_source = re.sub(r"= WebClient\(", "= LegacyWebClient(", legacy_source) + legacy_source = re.sub(r"^from slack_sdk.web.chat_stream import ChatStream\n", "", legacy_source, flags=re.MULTILINE) + legacy_source = re.sub(r"(?s)def chat_stream.*?(?=def)", "", legacy_source) with open(f"{args.path}/slack_sdk/web/legacy_client.py", "w") as output: output.write(legacy_source) + +with open(f"{args.path}/slack_sdk/web/chat_stream.py", "r") as original: + source = original.read() + import re + + async_source = header + source + async_source = re.sub( + "from slack_sdk.web.slack_response import SlackResponse", + "from slack_sdk.web.async_slack_response import AsyncSlackResponse", + async_source, + ) + async_source = re.sub( + r"from slack_sdk import WebClient", + "from slack_sdk.web.async_client import AsyncWebClient", + async_source, + ) + async_source = re.sub("class ChatStream", "class AsyncChatStream", async_source) + async_source = re.sub('"WebClient"', '"AsyncWebClient"', async_source) + async_source = re.sub(r"Optional\[SlackResponse\]", "Optional[AsyncSlackResponse]", async_source) + async_source = re.sub(r"SlackResponse ", "AsyncSlackResponse ", async_source) + async_source = re.sub(r"SlackResponse:", "AsyncSlackResponse:", async_source) + async_source = re.sub(r"def append\(", "async def append(", async_source) + async_source = re.sub(r"def stop\(", "async def stop(", async_source) + async_source = re.sub(r"def _flush_buffer\(", "async def _flush_buffer(", async_source) + async_source = re.sub("self._client.chat_", "await self._client.chat_", async_source) + async_source = re.sub("self._flush_buffer", "await self._flush_buffer", async_source) + with open(f"{args.path}/slack_sdk/web/async_chat_stream.py", "w") as output: + output.write(async_source) diff --git a/slack_sdk/web/async_chat_stream.py b/slack_sdk/web/async_chat_stream.py new file mode 100644 index 000000000..4661f19dd --- /dev/null +++ b/slack_sdk/web/async_chat_stream.py @@ -0,0 +1,212 @@ +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +# +# *** DO NOT EDIT THIS FILE *** +# +# 1) Modify slack_sdk/web/client.py +# 2) Run `python scripts/codegen.py` +# 3) Run `black slack_sdk/` +# +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +import json +import logging +from typing import TYPE_CHECKING, Dict, Optional, Sequence, Union + +import slack_sdk.errors as e +from slack_sdk.models.blocks.blocks import Block +from slack_sdk.models.metadata import Metadata +from slack_sdk.web.async_slack_response import AsyncSlackResponse + +if TYPE_CHECKING: + from slack_sdk.web.async_client import AsyncWebClient + + +class AsyncChatStream: + """A helper class for streaming markdown text into a conversation using the chat streaming APIs. + + This class provides a convenient interface for the chat.startStream, chat.appendStream, and chat.stopStream API + methods, with automatic buffering and state management. + """ + + def __init__( + self, + client: "AsyncWebClient", + *, + channel: str, + logger: logging.Logger, + thread_ts: str, + buffer_size: int, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, + **kwargs, + ): + """Initialize a new ChatStream instance. + + The __init__ method creates a unique ChatStream instance that keeps track of one chat stream. + + Args: + client: The WebClient instance to use for API calls. + channel: An encoded ID that represents a channel, private group, or DM. + logger: A logging channel for outputs. + thread_ts: Provide another message's ts value to reply to. Streamed messages should always be replies to a user + request. + recipient_team_id: The encoded ID of the team the user receiving the streaming text belongs to. Required when + streaming to channels. + recipient_user_id: The encoded ID of the user to receive the streaming text. Required when streaming to channels. + buffer_size: The length of markdown_text to buffer in-memory before calling a method. Increasing this value + decreases the number of method calls made for the same amount of text, which is useful to avoid rate limits. + **kwargs: Additional arguments passed to the underlying API calls. + """ + self._client = client + self._logger = logger + self._token: Optional[str] = kwargs.pop("token", None) + self._stream_args = { + "channel": channel, + "thread_ts": thread_ts, + "recipient_team_id": recipient_team_id, + "recipient_user_id": recipient_user_id, + **kwargs, + } + self._buffer = "" + self._state = "starting" + self._stream_ts: Optional[str] = None + self._buffer_size = buffer_size + + async def append( + self, + *, + markdown_text: str, + **kwargs, + ) -> Optional[AsyncSlackResponse]: + """Append to the stream. + + The "append" method appends to the chat stream being used. This method can be called multiple times. After the stream + is stopped this method cannot be called. + + Args: + markdown_text: Accepts message text formatted in markdown. Limit this field to 12,000 characters. This text is + what will be appended to the message received so far. + **kwargs: Additional arguments passed to the underlying API calls. + + Returns: + AsyncSlackResponse if the buffer was flushed, None if buffering. + + Raises: + SlackRequestError: If the stream is already completed. + + Example: + ```python + streamer = client.chat_stream( + channel="C0123456789", + thread_ts="1700000001.123456", + recipient_team_id="T0123456789", + recipient_user_id="U0123456789", + ) + streamer.append(markdown_text="**hello wo") + streamer.append(markdown_text="rld!**") + streamer.stop() + ``` + """ + if self._state == "completed": + raise e.SlackRequestError(f"Cannot append to stream: stream state is {self._state}") + if kwargs.get("token"): + self._token = kwargs.pop("token") + self._buffer += markdown_text + if len(self._buffer) >= self._buffer_size: + return await self._flush_buffer(**kwargs) + details = { + "buffer_length": len(self._buffer), + "buffer_size": self._buffer_size, + "channel": self._stream_args.get("channel"), + "recipient_team_id": self._stream_args.get("recipient_team_id"), + "recipient_user_id": self._stream_args.get("recipient_user_id"), + "thread_ts": self._stream_args.get("thread_ts"), + } + self._logger.debug(f"ChatStream appended to buffer: {json.dumps(details)}") + return None + + async def stop( + self, + *, + markdown_text: Optional[str] = None, + blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, + metadata: Optional[Union[Dict, Metadata]] = None, + **kwargs, + ) -> AsyncSlackResponse: + """Stop the stream and finalize the message. + + Args: + blocks: A list of blocks that will be rendered at the bottom of the finalized message. + markdown_text: Accepts message text formatted in markdown. Limit this field to 12,000 characters. This text is + what will be appended to the message received so far. + metadata: JSON object with event_type and event_payload fields, presented as a URL-encoded string. Metadata you + post to Slack is accessible to any app or user who is a member of that workspace. + **kwargs: Additional arguments passed to the underlying API calls. + + Returns: + AsyncSlackResponse from the chat.stopStream API call. + + Raises: + SlackRequestError: If the stream is already completed. + + Example: + ```python + streamer = client.chat_stream( + channel="C0123456789", + thread_ts="1700000001.123456", + recipient_team_id="T0123456789", + recipient_user_id="U0123456789", + ) + streamer.append(markdown_text="**hello wo") + streamer.append(markdown_text="rld!**") + streamer.stop() + ``` + """ + if self._state == "completed": + raise e.SlackRequestError(f"Cannot stop stream: stream state is {self._state}") + if kwargs.get("token"): + self._token = kwargs.pop("token") + if markdown_text: + self._buffer += markdown_text + if not self._stream_ts: + response = await self._client.chat_startStream( + **self._stream_args, + token=self._token, + ) + if not response.get("ts"): + raise e.SlackRequestError("Failed to stop stream: stream not started") + self._stream_ts = str(response["ts"]) + self._state = "in_progress" + response = await self._client.chat_stopStream( + token=self._token, + channel=self._stream_args["channel"], + ts=self._stream_ts, + blocks=blocks, + markdown_text=self._buffer, + metadata=metadata, + **kwargs, + ) + self._state = "completed" + return response + + async def _flush_buffer(self, **kwargs) -> AsyncSlackResponse: + """Flush the internal buffer by making appropriate API calls.""" + if not self._stream_ts: + response = await self._client.chat_startStream( + **self._stream_args, + token=self._token, + **kwargs, + markdown_text=self._buffer, + ) + self._stream_ts = response.get("ts") + self._state = "in_progress" + else: + response = await self._client.chat_appendStream( + token=self._token, + channel=self._stream_args["channel"], + ts=self._stream_ts, + **kwargs, + markdown_text=self._buffer, + ) + self._buffer = "" + return response diff --git a/slack_sdk/web/async_client.py b/slack_sdk/web/async_client.py index 3f30bad5a..f4aa8a17f 100644 --- a/slack_sdk/web/async_client.py +++ b/slack_sdk/web/async_client.py @@ -18,6 +18,7 @@ import slack_sdk.errors as e from slack_sdk.models.views import View +from slack_sdk.web.async_chat_stream import AsyncChatStream from ..models.attachments import Attachment from ..models.blocks import Block @@ -2930,6 +2931,69 @@ async def chat_stopStream( kwargs = _remove_none_values(kwargs) return await self.api_call("chat.stopStream", json=kwargs) + async def chat_stream( + self, + *, + buffer_size: int = 256, + channel: str, + thread_ts: str, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, + **kwargs, + ) -> AsyncChatStream: + """Stream markdown text into a conversation. + + This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, + the stream can be stopped with concluding arguments such as "blocks" for gathering feedback. + + The following methods are used: + + - chat.startStream: Starts a new streaming conversation. + [Reference](https://docs.slack.dev/reference/methods/chat.startStream). + - chat.appendStream: Appends text to an existing streaming conversation. + [Reference](https://docs.slack.dev/reference/methods/chat.appendStream). + - chat.stopStream: Stops a streaming conversation. + [Reference](https://docs.slack.dev/reference/methods/chat.stopStream). + + Args: + buffer_size: The length of markdown_text to buffer in-memory before calling a stream method. Increasing this + value decreases the number of method calls made for the same amount of text, which is useful to avoid rate + limits. Default: 256. + channel: An encoded ID that represents a channel, private group, or DM. + thread_ts: Provide another message's ts value to reply to. Streamed messages should always be replies to a user + request. + recipient_team_id: The encoded ID of the team the user receiving the streaming text belongs to. Required when + streaming to channels. + recipient_user_id: The encoded ID of the user to receive the streaming text. Required when streaming to channels. + **kwargs: Additional arguments passed to the underlying API calls. + + Returns: + ChatStream instance for managing the stream + + Example: + ```python + streamer = await client.chat_stream( + channel="C0123456789", + thread_ts="1700000001.123456", + recipient_team_id="T0123456789", + recipient_user_id="U0123456789", + ) + await streamer.append(markdown_text="**hello wo") + await streamer.append(markdown_text="rld!**") + await streamer.stop() + ``` + """ + return AsyncChatStream( + self, + logger=self._logger, + channel=channel, + thread_ts=thread_ts, + recipient_team_id=recipient_team_id, + recipient_user_id=recipient_user_id, + buffer_size=buffer_size, + **kwargs, + ) + async def chat_unfurl( self, *, diff --git a/slack_sdk/web/chat_stream.py b/slack_sdk/web/chat_stream.py new file mode 100644 index 000000000..1a379c9cb --- /dev/null +++ b/slack_sdk/web/chat_stream.py @@ -0,0 +1,202 @@ +import json +import logging +from typing import TYPE_CHECKING, Dict, Optional, Sequence, Union + +import slack_sdk.errors as e +from slack_sdk.models.blocks.blocks import Block +from slack_sdk.models.metadata import Metadata +from slack_sdk.web.slack_response import SlackResponse + +if TYPE_CHECKING: + from slack_sdk import WebClient + + +class ChatStream: + """A helper class for streaming markdown text into a conversation using the chat streaming APIs. + + This class provides a convenient interface for the chat.startStream, chat.appendStream, and chat.stopStream API + methods, with automatic buffering and state management. + """ + + def __init__( + self, + client: "WebClient", + *, + channel: str, + logger: logging.Logger, + thread_ts: str, + buffer_size: int, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, + **kwargs, + ): + """Initialize a new ChatStream instance. + + The __init__ method creates a unique ChatStream instance that keeps track of one chat stream. + + Args: + client: The WebClient instance to use for API calls. + channel: An encoded ID that represents a channel, private group, or DM. + logger: A logging channel for outputs. + thread_ts: Provide another message's ts value to reply to. Streamed messages should always be replies to a user + request. + recipient_team_id: The encoded ID of the team the user receiving the streaming text belongs to. Required when + streaming to channels. + recipient_user_id: The encoded ID of the user to receive the streaming text. Required when streaming to channels. + buffer_size: The length of markdown_text to buffer in-memory before calling a method. Increasing this value + decreases the number of method calls made for the same amount of text, which is useful to avoid rate limits. + **kwargs: Additional arguments passed to the underlying API calls. + """ + self._client = client + self._logger = logger + self._token: Optional[str] = kwargs.pop("token", None) + self._stream_args = { + "channel": channel, + "thread_ts": thread_ts, + "recipient_team_id": recipient_team_id, + "recipient_user_id": recipient_user_id, + **kwargs, + } + self._buffer = "" + self._state = "starting" + self._stream_ts: Optional[str] = None + self._buffer_size = buffer_size + + def append( + self, + *, + markdown_text: str, + **kwargs, + ) -> Optional[SlackResponse]: + """Append to the stream. + + The "append" method appends to the chat stream being used. This method can be called multiple times. After the stream + is stopped this method cannot be called. + + Args: + markdown_text: Accepts message text formatted in markdown. Limit this field to 12,000 characters. This text is + what will be appended to the message received so far. + **kwargs: Additional arguments passed to the underlying API calls. + + Returns: + SlackResponse if the buffer was flushed, None if buffering. + + Raises: + SlackRequestError: If the stream is already completed. + + Example: + ```python + streamer = client.chat_stream( + channel="C0123456789", + thread_ts="1700000001.123456", + recipient_team_id="T0123456789", + recipient_user_id="U0123456789", + ) + streamer.append(markdown_text="**hello wo") + streamer.append(markdown_text="rld!**") + streamer.stop() + ``` + """ + if self._state == "completed": + raise e.SlackRequestError(f"Cannot append to stream: stream state is {self._state}") + if kwargs.get("token"): + self._token = kwargs.pop("token") + self._buffer += markdown_text + if len(self._buffer) >= self._buffer_size: + return self._flush_buffer(**kwargs) + details = { + "buffer_length": len(self._buffer), + "buffer_size": self._buffer_size, + "channel": self._stream_args.get("channel"), + "recipient_team_id": self._stream_args.get("recipient_team_id"), + "recipient_user_id": self._stream_args.get("recipient_user_id"), + "thread_ts": self._stream_args.get("thread_ts"), + } + self._logger.debug(f"ChatStream appended to buffer: {json.dumps(details)}") + return None + + def stop( + self, + *, + markdown_text: Optional[str] = None, + blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, + metadata: Optional[Union[Dict, Metadata]] = None, + **kwargs, + ) -> SlackResponse: + """Stop the stream and finalize the message. + + Args: + blocks: A list of blocks that will be rendered at the bottom of the finalized message. + markdown_text: Accepts message text formatted in markdown. Limit this field to 12,000 characters. This text is + what will be appended to the message received so far. + metadata: JSON object with event_type and event_payload fields, presented as a URL-encoded string. Metadata you + post to Slack is accessible to any app or user who is a member of that workspace. + **kwargs: Additional arguments passed to the underlying API calls. + + Returns: + SlackResponse from the chat.stopStream API call. + + Raises: + SlackRequestError: If the stream is already completed. + + Example: + ```python + streamer = client.chat_stream( + channel="C0123456789", + thread_ts="1700000001.123456", + recipient_team_id="T0123456789", + recipient_user_id="U0123456789", + ) + streamer.append(markdown_text="**hello wo") + streamer.append(markdown_text="rld!**") + streamer.stop() + ``` + """ + if self._state == "completed": + raise e.SlackRequestError(f"Cannot stop stream: stream state is {self._state}") + if kwargs.get("token"): + self._token = kwargs.pop("token") + if markdown_text: + self._buffer += markdown_text + if not self._stream_ts: + response = self._client.chat_startStream( + **self._stream_args, + token=self._token, + ) + if not response.get("ts"): + raise e.SlackRequestError("Failed to stop stream: stream not started") + self._stream_ts = str(response["ts"]) + self._state = "in_progress" + response = self._client.chat_stopStream( + token=self._token, + channel=self._stream_args["channel"], + ts=self._stream_ts, + blocks=blocks, + markdown_text=self._buffer, + metadata=metadata, + **kwargs, + ) + self._state = "completed" + return response + + def _flush_buffer(self, **kwargs) -> SlackResponse: + """Flush the internal buffer by making appropriate API calls.""" + if not self._stream_ts: + response = self._client.chat_startStream( + **self._stream_args, + token=self._token, + **kwargs, + markdown_text=self._buffer, + ) + self._stream_ts = response.get("ts") + self._state = "in_progress" + else: + response = self._client.chat_appendStream( + token=self._token, + channel=self._stream_args["channel"], + ts=self._stream_ts, + **kwargs, + markdown_text=self._buffer, + ) + self._buffer = "" + return response diff --git a/slack_sdk/web/client.py b/slack_sdk/web/client.py index 8c15f983f..f95a2a726 100644 --- a/slack_sdk/web/client.py +++ b/slack_sdk/web/client.py @@ -8,6 +8,7 @@ import slack_sdk.errors as e from slack_sdk.models.views import View +from slack_sdk.web.chat_stream import ChatStream from ..models.attachments import Attachment from ..models.blocks import Block @@ -2920,6 +2921,69 @@ def chat_stopStream( kwargs = _remove_none_values(kwargs) return self.api_call("chat.stopStream", json=kwargs) + def chat_stream( + self, + *, + buffer_size: int = 256, + channel: str, + thread_ts: str, + recipient_team_id: Optional[str] = None, + recipient_user_id: Optional[str] = None, + **kwargs, + ) -> ChatStream: + """Stream markdown text into a conversation. + + This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, + the stream can be stopped with concluding arguments such as "blocks" for gathering feedback. + + The following methods are used: + + - chat.startStream: Starts a new streaming conversation. + [Reference](https://docs.slack.dev/reference/methods/chat.startStream). + - chat.appendStream: Appends text to an existing streaming conversation. + [Reference](https://docs.slack.dev/reference/methods/chat.appendStream). + - chat.stopStream: Stops a streaming conversation. + [Reference](https://docs.slack.dev/reference/methods/chat.stopStream). + + Args: + buffer_size: The length of markdown_text to buffer in-memory before calling a stream method. Increasing this + value decreases the number of method calls made for the same amount of text, which is useful to avoid rate + limits. Default: 256. + channel: An encoded ID that represents a channel, private group, or DM. + thread_ts: Provide another message's ts value to reply to. Streamed messages should always be replies to a user + request. + recipient_team_id: The encoded ID of the team the user receiving the streaming text belongs to. Required when + streaming to channels. + recipient_user_id: The encoded ID of the user to receive the streaming text. Required when streaming to channels. + **kwargs: Additional arguments passed to the underlying API calls. + + Returns: + ChatStream instance for managing the stream + + Example: + ```python + streamer = client.chat_stream( + channel="C0123456789", + thread_ts="1700000001.123456", + recipient_team_id="T0123456789", + recipient_user_id="U0123456789", + ) + streamer.append(markdown_text="**hello wo") + streamer.append(markdown_text="rld!**") + streamer.stop() + ``` + """ + return ChatStream( + self, + logger=self._logger, + channel=channel, + thread_ts=thread_ts, + recipient_team_id=recipient_team_id, + recipient_user_id=recipient_user_id, + buffer_size=buffer_size, + **kwargs, + ) + def chat_unfurl( self, *, diff --git a/tests/slack_sdk/web/test_chat_stream.py b/tests/slack_sdk/web/test_chat_stream.py new file mode 100644 index 000000000..75c13c8c2 --- /dev/null +++ b/tests/slack_sdk/web/test_chat_stream.py @@ -0,0 +1,188 @@ +import json +import unittest +from urllib.parse import parse_qs, urlparse + +from slack_sdk import WebClient +from slack_sdk.errors import SlackRequestError +from slack_sdk.models.blocks.basic_components import FeedbackButtonObject +from slack_sdk.models.blocks.block_elements import FeedbackButtonsElement, IconButtonElement +from slack_sdk.models.blocks.blocks import ContextActionsBlock +from tests.mock_web_api_server import cleanup_mock_web_api_server, setup_mock_web_api_server +from tests.slack_sdk.web.mock_web_api_handler import MockHandler + + +class ChatStreamMockHandler(MockHandler): + """Extended mock handler that captures request bodies for chat stream methods""" + + def _handle(self): + try: + # put_nowait is common between Queue & asyncio.Queue, it does not need to be awaited + self.server.queue.put_nowait(self.path) + + # Standard auth and validation from parent + if self.is_valid_token() and self.is_valid_user_agent(): + token = self.headers["authorization"].split(" ")[1] + parsed_path = urlparse(self.path) + len_header = self.headers.get("Content-Length") or 0 + content_len = int(len_header) + post_body = self.rfile.read(content_len) + request_body = None + if post_body: + try: + post_body = post_body.decode("utf-8") + if post_body.startswith("{"): + request_body = json.loads(post_body) + else: + request_body = {k: v[0] for k, v in parse_qs(post_body).items()} + except UnicodeDecodeError: + pass + else: + if parsed_path and parsed_path.query: + request_body = {k: v[0] for k, v in parse_qs(parsed_path.query).items()} + + # Store request body for chat stream endpoints + if self.path in ["/chat.startStream", "/chat.appendStream", "/chat.stopStream"] and request_body: + if not hasattr(self.server, "chat_stream_requests"): + self.server.chat_stream_requests = {} + self.server.chat_stream_requests[self.path] = { + "token": token, + **request_body, + } + + # Load response file + pattern = str(token).split("xoxb-", 1)[1] + with open(f"tests/slack_sdk_fixture/web_response_{pattern}.json") as file: + body = json.load(file) + + else: + body = self.invalid_auth + + if not body: + body = self.not_found + + self.send_response(200) + self.set_common_headers() + self.wfile.write(json.dumps(body).encode("utf-8")) + self.wfile.close() + + except Exception as e: + self.logger.error(str(e), exc_info=True) + raise + + +class TestChatStream(unittest.TestCase): + def setUp(self): + setup_mock_web_api_server(self, ChatStreamMockHandler) + self.client = WebClient( + token="xoxb-chat_stream_test", + base_url="http://localhost:8888", + ) + + def tearDown(self): + cleanup_mock_web_api_server(self) + + def test_streams_a_short_message(self): + streamer = self.client.chat_stream( + channel="C0123456789", + thread_ts="123.000", + recipient_team_id="T0123456789", + recipient_user_id="U0123456789", + ) + streamer.append(markdown_text="nice!") + streamer.stop() + + self.assertEqual(self.received_requests.get("/chat.startStream", 0), 1) + self.assertEqual(self.received_requests.get("/chat.appendStream", 0), 0) + self.assertEqual(self.received_requests.get("/chat.stopStream", 0), 1) + + if hasattr(self.thread.server, "chat_stream_requests"): + start_request = self.thread.server.chat_stream_requests.get("/chat.startStream", {}) + self.assertEqual(start_request.get("channel"), "C0123456789") + self.assertEqual(start_request.get("thread_ts"), "123.000") + self.assertEqual(start_request.get("recipient_team_id"), "T0123456789") + self.assertEqual(start_request.get("recipient_user_id"), "U0123456789") + + stop_request = self.thread.server.chat_stream_requests.get("/chat.stopStream", {}) + self.assertEqual(stop_request.get("channel"), "C0123456789") + self.assertEqual(stop_request.get("ts"), "123.123") + self.assertEqual(stop_request.get("markdown_text"), "nice!") + + def test_streams_a_long_message(self): + streamer = self.client.chat_stream( + buffer_size=5, + channel="C0123456789", + recipient_team_id="T0123456789", + recipient_user_id="U0123456789", + thread_ts="123.000", + ) + streamer.append(markdown_text="**this messag") + streamer.append(markdown_text="e is", token="xoxb-chat_stream_test_token1") + streamer.append(markdown_text=" bold!") + streamer.append(markdown_text="*") + streamer.stop( + blocks=[ + ContextActionsBlock( + elements=[ + FeedbackButtonsElement( + positive_button=FeedbackButtonObject(text="good", value="+1"), + negative_button=FeedbackButtonObject(text="bad", value="-1"), + ), + IconButtonElement( + icon="trash", + text="delete", + ), + ], + ) + ], + markdown_text="*", + token="xoxb-chat_stream_test_token2", + ) + + self.assertEqual(self.received_requests.get("/chat.startStream", 0), 1) + self.assertEqual(self.received_requests.get("/chat.appendStream", 0), 1) + self.assertEqual(self.received_requests.get("/chat.stopStream", 0), 1) + + if hasattr(self.thread.server, "chat_stream_requests"): + start_request = self.thread.server.chat_stream_requests.get("/chat.startStream", {}) + self.assertEqual(start_request.get("channel"), "C0123456789") + self.assertEqual(start_request.get("thread_ts"), "123.000") + self.assertEqual(start_request.get("markdown_text"), "**this messag") + self.assertEqual(start_request.get("recipient_team_id"), "T0123456789") + self.assertEqual(start_request.get("recipient_user_id"), "U0123456789") + + append_request = self.thread.server.chat_stream_requests.get("/chat.appendStream", {}) + self.assertEqual(append_request.get("channel"), "C0123456789") + self.assertEqual(append_request.get("markdown_text"), "e is bold!") + self.assertEqual(append_request.get("token"), "xoxb-chat_stream_test_token1") + self.assertEqual(append_request.get("ts"), "123.123") + + stop_request = self.thread.server.chat_stream_requests.get("/chat.stopStream", {}) + self.assertEqual( + json.dumps(stop_request.get("blocks")), + '[{"elements": [{"negative_button": {"text": {"emoji": true, "text": "bad", "type": "plain_text"}, "value": "-1"}, "positive_button": {"text": {"emoji": true, "text": "good", "type": "plain_text"}, "value": "+1"}, "type": "feedback_buttons"}, {"icon": "trash", "text": {"emoji": true, "text": "delete", "type": "plain_text"}, "type": "icon_button"}], "type": "context_actions"}]', + ) + self.assertEqual(stop_request.get("channel"), "C0123456789") + self.assertEqual(stop_request.get("markdown_text"), "**") + self.assertEqual(stop_request.get("token"), "xoxb-chat_stream_test_token2") + self.assertEqual(stop_request.get("ts"), "123.123") + + def test_streams_errors_when_appending_to_an_unstarted_stream(self): + streamer = self.client.chat_stream( + channel="C0123456789", + thread_ts="123.000", + token="xoxb-chat_stream_test_missing_ts", + ) + with self.assertRaisesRegex(SlackRequestError, r"^Failed to stop stream: stream not started$"): + streamer.stop() + + def test_streams_errors_when_appending_to_a_completed_stream(self): + streamer = self.client.chat_stream( + channel="C0123456789", + thread_ts="123.000", + ) + streamer.append(markdown_text="nice!") + streamer.stop() + with self.assertRaisesRegex(SlackRequestError, r"^Cannot append to stream: stream state is completed$"): + streamer.append(markdown_text="more...") + with self.assertRaisesRegex(SlackRequestError, r"^Cannot stop stream: stream state is completed$"): + streamer.stop() diff --git a/tests/slack_sdk_async/web/test_async_chat_stream.py b/tests/slack_sdk_async/web/test_async_chat_stream.py new file mode 100644 index 000000000..212fee1e2 --- /dev/null +++ b/tests/slack_sdk_async/web/test_async_chat_stream.py @@ -0,0 +1,193 @@ +import json +import unittest +from urllib.parse import parse_qs, urlparse + +from slack_sdk.errors import SlackRequestError +from slack_sdk.models.blocks.basic_components import FeedbackButtonObject +from slack_sdk.models.blocks.block_elements import FeedbackButtonsElement, IconButtonElement +from slack_sdk.models.blocks.blocks import ContextActionsBlock +from slack_sdk.web.async_client import AsyncWebClient +from tests.mock_web_api_server import cleanup_mock_web_api_server, setup_mock_web_api_server +from tests.slack_sdk.web.mock_web_api_handler import MockHandler +from tests.slack_sdk_async.helpers import async_test + + +class ChatStreamMockHandler(MockHandler): + """Extended mock handler that captures request bodies for chat stream methods""" + + def _handle(self): + try: + # put_nowait is common between Queue & asyncio.Queue, it does not need to be awaited + self.server.queue.put_nowait(self.path) + + # Standard auth and validation from parent + if self.is_valid_token() and self.is_valid_user_agent(): + token = self.headers["authorization"].split(" ")[1] + parsed_path = urlparse(self.path) + len_header = self.headers.get("Content-Length") or 0 + content_len = int(len_header) + post_body = self.rfile.read(content_len) + request_body = None + if post_body: + try: + post_body = post_body.decode("utf-8") + if post_body.startswith("{"): + request_body = json.loads(post_body) + else: + request_body = {k: v[0] for k, v in parse_qs(post_body).items()} + except UnicodeDecodeError: + pass + else: + if parsed_path and parsed_path.query: + request_body = {k: v[0] for k, v in parse_qs(parsed_path.query).items()} + + # Store request body for chat stream endpoints + if self.path in ["/chat.startStream", "/chat.appendStream", "/chat.stopStream"] and request_body: + if not hasattr(self.server, "chat_stream_requests"): + self.server.chat_stream_requests = {} + self.server.chat_stream_requests[self.path] = { + "token": token, + **request_body, + } + + # Load response file + pattern = str(token).split("xoxb-", 1)[1] + with open(f"tests/slack_sdk_fixture/web_response_{pattern}.json") as file: + body = json.load(file) + + else: + body = self.invalid_auth + + if not body: + body = self.not_found + + self.send_response(200) + self.set_common_headers() + self.wfile.write(json.dumps(body).encode("utf-8")) + self.wfile.close() + + except Exception as e: + self.logger.error(str(e), exc_info=True) + raise + + +class TestAsyncChatStream(unittest.TestCase): + def setUp(self): + setup_mock_web_api_server(self, ChatStreamMockHandler) + self.client = AsyncWebClient( + token="xoxb-chat_stream_test", + base_url="http://localhost:8888", + ) + + def tearDown(self): + cleanup_mock_web_api_server(self) + + @async_test + async def test_streams_a_short_message(self): + streamer = await self.client.chat_stream( + channel="C0123456789", + thread_ts="123.000", + recipient_team_id="T0123456789", + recipient_user_id="U0123456789", + ) + await streamer.append(markdown_text="nice!") + await streamer.stop() + + self.assertEqual(self.received_requests.get("/chat.startStream", 0), 1) + self.assertEqual(self.received_requests.get("/chat.appendStream", 0), 0) + self.assertEqual(self.received_requests.get("/chat.stopStream", 0), 1) + + if hasattr(self.thread.server, "chat_stream_requests"): + start_request = self.thread.server.chat_stream_requests.get("/chat.startStream", {}) + self.assertEqual(start_request.get("channel"), "C0123456789") + self.assertEqual(start_request.get("thread_ts"), "123.000") + self.assertEqual(start_request.get("recipient_team_id"), "T0123456789") + self.assertEqual(start_request.get("recipient_user_id"), "U0123456789") + + stop_request = self.thread.server.chat_stream_requests.get("/chat.stopStream", {}) + self.assertEqual(stop_request.get("channel"), "C0123456789") + self.assertEqual(stop_request.get("ts"), "123.123") + self.assertEqual(stop_request.get("markdown_text"), "nice!") + + @async_test + async def test_streams_a_long_message(self): + streamer = await self.client.chat_stream( + buffer_size=5, + channel="C0123456789", + recipient_team_id="T0123456789", + recipient_user_id="U0123456789", + thread_ts="123.000", + ) + await streamer.append(markdown_text="**this messag") + await streamer.append(markdown_text="e is", token="xoxb-chat_stream_test_token1") + await streamer.append(markdown_text=" bold!") + await streamer.append(markdown_text="*") + await streamer.stop( + blocks=[ + ContextActionsBlock( + elements=[ + FeedbackButtonsElement( + positive_button=FeedbackButtonObject(text="good", value="+1"), + negative_button=FeedbackButtonObject(text="bad", value="-1"), + ), + IconButtonElement( + icon="trash", + text="delete", + ), + ], + ) + ], + markdown_text="*", + token="xoxb-chat_stream_test_token2", + ) + + self.assertEqual(self.received_requests.get("/chat.startStream", 0), 1) + self.assertEqual(self.received_requests.get("/chat.appendStream", 0), 1) + self.assertEqual(self.received_requests.get("/chat.stopStream", 0), 1) + + if hasattr(self.thread.server, "chat_stream_requests"): + start_request = self.thread.server.chat_stream_requests.get("/chat.startStream", {}) + self.assertEqual(start_request.get("channel"), "C0123456789") + self.assertEqual(start_request.get("thread_ts"), "123.000") + self.assertEqual(start_request.get("markdown_text"), "**this messag") + self.assertEqual(start_request.get("recipient_team_id"), "T0123456789") + self.assertEqual(start_request.get("recipient_user_id"), "U0123456789") + + append_request = self.thread.server.chat_stream_requests.get("/chat.appendStream", {}) + self.assertEqual(append_request.get("channel"), "C0123456789") + self.assertEqual(append_request.get("markdown_text"), "e is bold!") + self.assertEqual(append_request.get("token"), "xoxb-chat_stream_test_token1") + self.assertEqual(append_request.get("ts"), "123.123") + + stop_request = self.thread.server.chat_stream_requests.get("/chat.stopStream", {}) + self.assertEqual( + json.dumps(stop_request.get("blocks")), + '[{"elements": [{"negative_button": {"text": {"emoji": true, "text": "bad", "type": "plain_text"}, "value": "-1"}, "positive_button": {"text": {"emoji": true, "text": "good", "type": "plain_text"}, "value": "+1"}, "type": "feedback_buttons"}, {"icon": "trash", "text": {"emoji": true, "text": "delete", "type": "plain_text"}, "type": "icon_button"}], "type": "context_actions"}]', + ) + self.assertEqual(stop_request.get("channel"), "C0123456789") + self.assertEqual(stop_request.get("markdown_text"), "**") + self.assertEqual(stop_request.get("token"), "xoxb-chat_stream_test_token2") + self.assertEqual(stop_request.get("ts"), "123.123") + + @async_test + async def test_streams_errors_when_appending_to_an_unstarted_stream(self): + streamer = await self.client.chat_stream( + channel="C0123456789", + thread_ts="123.000", + token="xoxb-chat_stream_test_missing_ts", + ) + with self.assertRaisesRegex(SlackRequestError, r"^Failed to stop stream: stream not started$"): + await streamer.stop() + + @async_test + async def test_streams_errors_when_appending_to_a_completed_stream(self): + streamer = await self.client.chat_stream( + channel="C0123456789", + thread_ts="123.000", + ) + await streamer.append(markdown_text="nice!") + await streamer.stop() + with self.assertRaisesRegex(SlackRequestError, r"^Cannot append to stream: stream state is completed$"): + await streamer.append(markdown_text="more...") + with self.assertRaisesRegex(SlackRequestError, r"^Cannot stop stream: stream state is completed$"): + await streamer.stop() diff --git a/tests/slack_sdk_fixture/web_response_chat_stream_test.json b/tests/slack_sdk_fixture/web_response_chat_stream_test.json new file mode 100644 index 000000000..2b5f29d01 --- /dev/null +++ b/tests/slack_sdk_fixture/web_response_chat_stream_test.json @@ -0,0 +1,4 @@ +{ + "ok": true, + "ts": "123.123" +} diff --git a/tests/slack_sdk_fixture/web_response_chat_stream_test_missing_ts.json b/tests/slack_sdk_fixture/web_response_chat_stream_test_missing_ts.json new file mode 100644 index 000000000..0287aedde --- /dev/null +++ b/tests/slack_sdk_fixture/web_response_chat_stream_test_missing_ts.json @@ -0,0 +1,3 @@ +{ + "ok": true +} diff --git a/tests/slack_sdk_fixture/web_response_chat_stream_test_token1.json b/tests/slack_sdk_fixture/web_response_chat_stream_test_token1.json new file mode 100644 index 000000000..0287aedde --- /dev/null +++ b/tests/slack_sdk_fixture/web_response_chat_stream_test_token1.json @@ -0,0 +1,3 @@ +{ + "ok": true +} diff --git a/tests/slack_sdk_fixture/web_response_chat_stream_test_token2.json b/tests/slack_sdk_fixture/web_response_chat_stream_test_token2.json new file mode 100644 index 000000000..0287aedde --- /dev/null +++ b/tests/slack_sdk_fixture/web_response_chat_stream_test_token2.json @@ -0,0 +1,3 @@ +{ + "ok": true +} From 300421eb0f27359341bd96bd5e86aa770f4f2ec9 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Thu, 2 Oct 2025 11:36:38 -0700 Subject: [PATCH 15/21] fix(web-api): remove unfurl arguments from chat.startStream method (#1761) --- docs/reference/index.html | 10 +--------- docs/reference/web/async_client.html | 10 +--------- docs/reference/web/client.html | 10 +--------- docs/reference/web/index.html | 10 +--------- docs/reference/web/legacy_client.html | 10 +--------- slack_sdk/web/async_client.py | 4 ---- slack_sdk/web/client.py | 4 ---- slack_sdk/web/legacy_client.py | 4 ---- 8 files changed, 5 insertions(+), 57 deletions(-) diff --git a/docs/reference/index.html b/docs/reference/index.html index 3cfd45f3f..a48e4687f 100644 --- a/docs/reference/index.html +++ b/docs/reference/index.html @@ -3009,8 +3009,6 @@

                  Classes

                  markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, - unfurl_links: Optional[bool] = None, - unfurl_media: Optional[bool] = None, **kwargs, ) -> SlackResponse: """Starts a new streaming conversation. @@ -3023,8 +3021,6 @@

                  Classes

                  "markdown_text": markdown_text, "recipient_team_id": recipient_team_id, "recipient_user_id": recipient_user_id, - "unfurl_links": unfurl_links, - "unfurl_media": unfurl_media, } ) kwargs = _remove_none_values(kwargs) @@ -10333,7 +10329,7 @@

                  Methods

                  https://api.slack.com/methods/chat.scheduledMessages.list

              • -def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                unfurl_links: bool | None = None,
                unfurl_media: bool | None = None,
                **kwargs) ‑> SlackResponse
                +def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                **kwargs) ‑> SlackResponse
                @@ -10348,8 +10344,6 @@

                Methods

                markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, - unfurl_links: Optional[bool] = None, - unfurl_media: Optional[bool] = None, **kwargs, ) -> SlackResponse: """Starts a new streaming conversation. @@ -10362,8 +10356,6 @@

                Methods

                "markdown_text": markdown_text, "recipient_team_id": recipient_team_id, "recipient_user_id": recipient_user_id, - "unfurl_links": unfurl_links, - "unfurl_media": unfurl_media, } ) kwargs = _remove_none_values(kwargs) diff --git a/docs/reference/web/async_client.html b/docs/reference/web/async_client.html index 7a46cf18c..d2ddecfb3 100644 --- a/docs/reference/web/async_client.html +++ b/docs/reference/web/async_client.html @@ -2905,8 +2905,6 @@

                Classes

                markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, - unfurl_links: Optional[bool] = None, - unfurl_media: Optional[bool] = None, **kwargs, ) -> AsyncSlackResponse: """Starts a new streaming conversation. @@ -2919,8 +2917,6 @@

                Classes

                "markdown_text": markdown_text, "recipient_team_id": recipient_team_id, "recipient_user_id": recipient_user_id, - "unfurl_links": unfurl_links, - "unfurl_media": unfurl_media, } ) kwargs = _remove_none_values(kwargs) @@ -10229,7 +10225,7 @@

                Methods

                https://api.slack.com/methods/chat.scheduledMessages.list

                -async def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                unfurl_links: bool | None = None,
                unfurl_media: bool | None = None,
                **kwargs) ‑> AsyncSlackResponse
                +async def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                **kwargs) ‑> AsyncSlackResponse
                @@ -10244,8 +10240,6 @@

                Methods

                markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, - unfurl_links: Optional[bool] = None, - unfurl_media: Optional[bool] = None, **kwargs, ) -> AsyncSlackResponse: """Starts a new streaming conversation. @@ -10258,8 +10252,6 @@

                Methods

                "markdown_text": markdown_text, "recipient_team_id": recipient_team_id, "recipient_user_id": recipient_user_id, - "unfurl_links": unfurl_links, - "unfurl_media": unfurl_media, } ) kwargs = _remove_none_values(kwargs) diff --git a/docs/reference/web/client.html b/docs/reference/web/client.html index 162df0964..1f208b094 100644 --- a/docs/reference/web/client.html +++ b/docs/reference/web/client.html @@ -2905,8 +2905,6 @@

                Classes

                markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, - unfurl_links: Optional[bool] = None, - unfurl_media: Optional[bool] = None, **kwargs, ) -> SlackResponse: """Starts a new streaming conversation. @@ -2919,8 +2917,6 @@

                Classes

                "markdown_text": markdown_text, "recipient_team_id": recipient_team_id, "recipient_user_id": recipient_user_id, - "unfurl_links": unfurl_links, - "unfurl_media": unfurl_media, } ) kwargs = _remove_none_values(kwargs) @@ -10229,7 +10225,7 @@

                Methods

                https://api.slack.com/methods/chat.scheduledMessages.list

                -def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                unfurl_links: bool | None = None,
                unfurl_media: bool | None = None,
                **kwargs) ‑> SlackResponse
                +def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                **kwargs) ‑> SlackResponse
                @@ -10244,8 +10240,6 @@

                Methods

                markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, - unfurl_links: Optional[bool] = None, - unfurl_media: Optional[bool] = None, **kwargs, ) -> SlackResponse: """Starts a new streaming conversation. @@ -10258,8 +10252,6 @@

                Methods

                "markdown_text": markdown_text, "recipient_team_id": recipient_team_id, "recipient_user_id": recipient_user_id, - "unfurl_links": unfurl_links, - "unfurl_media": unfurl_media, } ) kwargs = _remove_none_values(kwargs) diff --git a/docs/reference/web/index.html b/docs/reference/web/index.html index c2df7f11f..ca8c9fcc1 100644 --- a/docs/reference/web/index.html +++ b/docs/reference/web/index.html @@ -3274,8 +3274,6 @@

                Raises

                markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, - unfurl_links: Optional[bool] = None, - unfurl_media: Optional[bool] = None, **kwargs, ) -> SlackResponse: """Starts a new streaming conversation. @@ -3288,8 +3286,6 @@

                Raises

                "markdown_text": markdown_text, "recipient_team_id": recipient_team_id, "recipient_user_id": recipient_user_id, - "unfurl_links": unfurl_links, - "unfurl_media": unfurl_media, } ) kwargs = _remove_none_values(kwargs) @@ -10598,7 +10594,7 @@

                Methods

                https://api.slack.com/methods/chat.scheduledMessages.list

                -def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                unfurl_links: bool | None = None,
                unfurl_media: bool | None = None,
                **kwargs) ‑> SlackResponse
                +def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                **kwargs) ‑> SlackResponse
                @@ -10613,8 +10609,6 @@

                Methods

                markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, - unfurl_links: Optional[bool] = None, - unfurl_media: Optional[bool] = None, **kwargs, ) -> SlackResponse: """Starts a new streaming conversation. @@ -10627,8 +10621,6 @@

                Methods

                "markdown_text": markdown_text, "recipient_team_id": recipient_team_id, "recipient_user_id": recipient_user_id, - "unfurl_links": unfurl_links, - "unfurl_media": unfurl_media, } ) kwargs = _remove_none_values(kwargs) diff --git a/docs/reference/web/legacy_client.html b/docs/reference/web/legacy_client.html index 1d4ebbed8..98fff7e17 100644 --- a/docs/reference/web/legacy_client.html +++ b/docs/reference/web/legacy_client.html @@ -2904,8 +2904,6 @@

                Classes

                markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, - unfurl_links: Optional[bool] = None, - unfurl_media: Optional[bool] = None, **kwargs, ) -> Union[Future, SlackResponse]: """Starts a new streaming conversation. @@ -2918,8 +2916,6 @@

                Classes

                "markdown_text": markdown_text, "recipient_team_id": recipient_team_id, "recipient_user_id": recipient_user_id, - "unfurl_links": unfurl_links, - "unfurl_media": unfurl_media, } ) kwargs = _remove_none_values(kwargs) @@ -10165,7 +10161,7 @@

                Methods

                https://api.slack.com/methods/chat.scheduledMessages.list

                -def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                unfurl_links: bool | None = None,
                unfurl_media: bool | None = None,
                **kwargs) ‑> _asyncio.Future | LegacySlackResponse
                +def chat_startStream(self,
                *,
                channel: str,
                thread_ts: str,
                markdown_text: str | None = None,
                recipient_team_id: str | None = None,
                recipient_user_id: str | None = None,
                **kwargs) ‑> _asyncio.Future | LegacySlackResponse
                @@ -10180,8 +10176,6 @@

                Methods

                markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, - unfurl_links: Optional[bool] = None, - unfurl_media: Optional[bool] = None, **kwargs, ) -> Union[Future, SlackResponse]: """Starts a new streaming conversation. @@ -10194,8 +10188,6 @@

                Methods

                "markdown_text": markdown_text, "recipient_team_id": recipient_team_id, "recipient_user_id": recipient_user_id, - "unfurl_links": unfurl_links, - "unfurl_media": unfurl_media, } ) kwargs = _remove_none_values(kwargs) diff --git a/slack_sdk/web/async_client.py b/slack_sdk/web/async_client.py index f4aa8a17f..afe62e508 100644 --- a/slack_sdk/web/async_client.py +++ b/slack_sdk/web/async_client.py @@ -2884,8 +2884,6 @@ async def chat_startStream( markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, - unfurl_links: Optional[bool] = None, - unfurl_media: Optional[bool] = None, **kwargs, ) -> AsyncSlackResponse: """Starts a new streaming conversation. @@ -2898,8 +2896,6 @@ async def chat_startStream( "markdown_text": markdown_text, "recipient_team_id": recipient_team_id, "recipient_user_id": recipient_user_id, - "unfurl_links": unfurl_links, - "unfurl_media": unfurl_media, } ) kwargs = _remove_none_values(kwargs) diff --git a/slack_sdk/web/client.py b/slack_sdk/web/client.py index f95a2a726..eef4b9f9f 100644 --- a/slack_sdk/web/client.py +++ b/slack_sdk/web/client.py @@ -2874,8 +2874,6 @@ def chat_startStream( markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, - unfurl_links: Optional[bool] = None, - unfurl_media: Optional[bool] = None, **kwargs, ) -> SlackResponse: """Starts a new streaming conversation. @@ -2888,8 +2886,6 @@ def chat_startStream( "markdown_text": markdown_text, "recipient_team_id": recipient_team_id, "recipient_user_id": recipient_user_id, - "unfurl_links": unfurl_links, - "unfurl_media": unfurl_media, } ) kwargs = _remove_none_values(kwargs) diff --git a/slack_sdk/web/legacy_client.py b/slack_sdk/web/legacy_client.py index 29ef99064..0594b857f 100644 --- a/slack_sdk/web/legacy_client.py +++ b/slack_sdk/web/legacy_client.py @@ -2885,8 +2885,6 @@ def chat_startStream( markdown_text: Optional[str] = None, recipient_team_id: Optional[str] = None, recipient_user_id: Optional[str] = None, - unfurl_links: Optional[bool] = None, - unfurl_media: Optional[bool] = None, **kwargs, ) -> Union[Future, SlackResponse]: """Starts a new streaming conversation. @@ -2899,8 +2897,6 @@ def chat_startStream( "markdown_text": markdown_text, "recipient_team_id": recipient_team_id, "recipient_user_id": recipient_user_id, - "unfurl_links": unfurl_links, - "unfurl_media": unfurl_media, } ) kwargs = _remove_none_values(kwargs) From 8330c20e03be6be5dfda46105ef05aa5a3f1885b Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Thu, 2 Oct 2025 11:47:11 -0700 Subject: [PATCH 16/21] chore(release): version 3.36.0.dev6 --- slack_sdk/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slack_sdk/version.py b/slack_sdk/version.py index 95e0f5493..56dbec8fc 100644 --- a/slack_sdk/version.py +++ b/slack_sdk/version.py @@ -1,3 +1,3 @@ """Check the latest version at https://pypi.org/project/slack-sdk/""" -__version__ = "3.36.0.dev5" +__version__ = "3.36.0.dev6" From 9f5604c4cfe714becfdb0b9169b7a80c6b2430b9 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Thu, 2 Oct 2025 21:44:49 -0700 Subject: [PATCH 17/21] docs: typo for conversations in chat stream docs (#1762) --- docs/reference/index.html | 6 +++--- docs/reference/web/async_client.html | 6 +++--- docs/reference/web/client.html | 6 +++--- docs/reference/web/index.html | 6 +++--- slack_sdk/web/async_client.py | 2 +- slack_sdk/web/client.py | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/reference/index.html b/docs/reference/index.html index a48e4687f..cd063afe8 100644 --- a/docs/reference/index.html +++ b/docs/reference/index.html @@ -3064,7 +3064,7 @@

                Classes

                ) -> ChatStream: """Stream markdown text into a conversation. - This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, + This method starts a new chat stream in a conversation that can be appended to. After appending an entire message, the stream can be stopped with concluding arguments such as "blocks" for gathering feedback. The following methods are used: @@ -10421,7 +10421,7 @@

                Methods

                ) -> ChatStream: """Stream markdown text into a conversation. - This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, + This method starts a new chat stream in a conversation that can be appended to. After appending an entire message, the stream can be stopped with concluding arguments such as "blocks" for gathering feedback. The following methods are used: @@ -10473,7 +10473,7 @@

                Methods

                )

                Stream markdown text into a conversation.

                -

                This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, +

                This method starts a new chat stream in a conversation that can be appended to. After appending an entire message, the stream can be stopped with concluding arguments such as "blocks" for gathering feedback.

                The following methods are used:

                  diff --git a/docs/reference/web/async_client.html b/docs/reference/web/async_client.html index d2ddecfb3..d1bd7df2a 100644 --- a/docs/reference/web/async_client.html +++ b/docs/reference/web/async_client.html @@ -2960,7 +2960,7 @@

                  Classes

                  ) -> AsyncChatStream: """Stream markdown text into a conversation. - This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, + This method starts a new chat stream in a conversation that can be appended to. After appending an entire message, the stream can be stopped with concluding arguments such as "blocks" for gathering feedback. The following methods are used: @@ -10317,7 +10317,7 @@

                  Methods

                  ) -> AsyncChatStream: """Stream markdown text into a conversation. - This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, + This method starts a new chat stream in a conversation that can be appended to. After appending an entire message, the stream can be stopped with concluding arguments such as "blocks" for gathering feedback. The following methods are used: @@ -10369,7 +10369,7 @@

                  Methods

                  )

                Stream markdown text into a conversation.

                -

                This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, +

                This method starts a new chat stream in a conversation that can be appended to. After appending an entire message, the stream can be stopped with concluding arguments such as "blocks" for gathering feedback.

                The following methods are used:

                  diff --git a/docs/reference/web/client.html b/docs/reference/web/client.html index 1f208b094..122cfed9f 100644 --- a/docs/reference/web/client.html +++ b/docs/reference/web/client.html @@ -2960,7 +2960,7 @@

                  Classes

                  ) -> ChatStream: """Stream markdown text into a conversation. - This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, + This method starts a new chat stream in a conversation that can be appended to. After appending an entire message, the stream can be stopped with concluding arguments such as "blocks" for gathering feedback. The following methods are used: @@ -10317,7 +10317,7 @@

                  Methods

                  ) -> ChatStream: """Stream markdown text into a conversation. - This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, + This method starts a new chat stream in a conversation that can be appended to. After appending an entire message, the stream can be stopped with concluding arguments such as "blocks" for gathering feedback. The following methods are used: @@ -10369,7 +10369,7 @@

                  Methods

                  )

                  Stream markdown text into a conversation.

                  -

                  This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, +

                  This method starts a new chat stream in a conversation that can be appended to. After appending an entire message, the stream can be stopped with concluding arguments such as "blocks" for gathering feedback.

                  The following methods are used:

                    diff --git a/docs/reference/web/index.html b/docs/reference/web/index.html index ca8c9fcc1..353347506 100644 --- a/docs/reference/web/index.html +++ b/docs/reference/web/index.html @@ -3329,7 +3329,7 @@

                    Raises

                    ) -> ChatStream: """Stream markdown text into a conversation. - This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, + This method starts a new chat stream in a conversation that can be appended to. After appending an entire message, the stream can be stopped with concluding arguments such as "blocks" for gathering feedback. The following methods are used: @@ -10686,7 +10686,7 @@

                    Methods

                    ) -> ChatStream: """Stream markdown text into a conversation. - This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, + This method starts a new chat stream in a conversation that can be appended to. After appending an entire message, the stream can be stopped with concluding arguments such as "blocks" for gathering feedback. The following methods are used: @@ -10738,7 +10738,7 @@

                    Methods

                    )

                    Stream markdown text into a conversation.

                    -

                    This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, +

                    This method starts a new chat stream in a conversation that can be appended to. After appending an entire message, the stream can be stopped with concluding arguments such as "blocks" for gathering feedback.

                    The following methods are used:

                      diff --git a/slack_sdk/web/async_client.py b/slack_sdk/web/async_client.py index afe62e508..a375e9cca 100644 --- a/slack_sdk/web/async_client.py +++ b/slack_sdk/web/async_client.py @@ -2939,7 +2939,7 @@ async def chat_stream( ) -> AsyncChatStream: """Stream markdown text into a conversation. - This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, + This method starts a new chat stream in a conversation that can be appended to. After appending an entire message, the stream can be stopped with concluding arguments such as "blocks" for gathering feedback. The following methods are used: diff --git a/slack_sdk/web/client.py b/slack_sdk/web/client.py index eef4b9f9f..e880fa45a 100644 --- a/slack_sdk/web/client.py +++ b/slack_sdk/web/client.py @@ -2929,7 +2929,7 @@ def chat_stream( ) -> ChatStream: """Stream markdown text into a conversation. - This method starts a new chat stream in a coversation that can be appended to. After appending an entire message, + This method starts a new chat stream in a conversation that can be appended to. After appending an entire message, the stream can be stopped with concluding arguments such as "blocks" for gathering feedback. The following methods are used: From 1a1b2b3520853dfc2e358ec4c6fec6cd74d822e3 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 3 Oct 2025 11:31:05 -0700 Subject: [PATCH 18/21] chore(release): version 3.36.0.dev7 --- slack_sdk/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slack_sdk/version.py b/slack_sdk/version.py index 56dbec8fc..f56594ea1 100644 --- a/slack_sdk/version.py +++ b/slack_sdk/version.py @@ -1,3 +1,3 @@ """Check the latest version at https://pypi.org/project/slack-sdk/""" -__version__ = "3.36.0.dev6" +__version__ = "3.36.0.dev7" From 28b191e20ff67fe9e6d0e787add22e6af53aa7b5 Mon Sep 17 00:00:00 2001 From: Luke Russell <31357343+lukegalbraithrussell@users.noreply.github.com> Date: Fri, 3 Oct 2025 15:07:54 -0700 Subject: [PATCH 19/21] docs: adds ai apps docs (#1764) * go * typo * go * Apply suggestions from code review Co-authored-by: Eden Zimbelman * full path --------- Co-authored-by: Eden Zimbelman --- docs/english/web.md | 110 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/docs/english/web.md b/docs/english/web.md index 5069e5461..0b689c530 100644 --- a/docs/english/web.md +++ b/docs/english/web.md @@ -33,6 +33,8 @@ except SlackApiError as e: assert e.response["error"] # str like 'invalid_auth', 'channel_not_found' ``` +### Sending ephemeral messages + Sending an ephemeral message, which is only visible to an assigned user in a specified channel, is nearly the same as sending a regular message but with an additional `user` parameter. ``` python @@ -51,6 +53,114 @@ response = client.chat_postEphemeral( See the [`chat.postEphemeral`](/reference/methods/chat.postEphemeral) API method for more details. +### Sending streaming messages {#sending-streaming-messages} + +You can have your app's messages stream in to replicate conventional AI chatbot behavior. This is done through three Web API methods: + +* [`chat_startStream`](/reference/methods/chat.startstream) +* [`chat_appendStream`](/reference/methods/chat.appendstream) +* [`chat_stopStream`](/reference/methods/chat.stopstream) + +:::tip [The Python Slack SDK provides a [`chat_stream()`](https://docs.slack.dev/tools/python-slack-sdk/reference/web/client.html#slack_sdk.web.client.WebClient.chat_stream) helper utility to streamline calling these methods.] + +See the [_Streaming messages_](/tools/bolt-python/concepts/message-sending#streaming-messages) section of the Bolt for Python docs for implementation instructions. + +::: + +#### Starting the message stream {#starting-stream} + +First you need to begin the message stream: + +```python +# Example: Stream a response to any message +@app.message() +def handle_message(message, client): + channel_id = event.get("channel") + team_id = event.get("team") + thread_ts = event.get("thread_ts") or event.get("ts") + user_id = event.get("user") + + # Start a new message stream + stream_response = client.chat_startStream( + channel=channel_id, + recipient_team_id=team_id, + recipient_user_id=user_id, + thread_ts=thread_ts, + ) + stream_ts = stream_response["ts"] +``` + +#### Appending content to the message stream {#appending-stream} + +With the stream started, you can then append text to it in chunks to convey a streaming effect. + +The structure of the text coming in will depend on your source. The following code snippet uses OpenAI's response structure as an example: + +```python +# continued from above + for event in returned_message: + if event.type == "response.output_text.delta": + client.chat_appendStream( + channel=channel_id, + ts=stream_ts, + markdown_text=f"{event.delta}" + ) + else: + continue +``` + +#### Stopping the message stream {#stopping-stream} + +Your app can then end the stream with the `chat_stopStream` method: + +```python +# continued from above + client.chat_stopStream( + channel=channel_id, + ts=stream_ts + ) +``` + +The method also provides you an opportunity to request user feedback on your app's responses using the [feedback buttons](/reference/block-kit/block-elements/feedback-buttons-element) block element within the [context actions](/reference/block-kit/blocks/context-actions-block) block. The user will be presented with thumbs up and thumbs down buttons which send an action to your app when pressed. + +```python +def create_feedback_block() -> List[Block]: + blocks: List[Block] = [ + ContextActionsBlock( + elements=[ + FeedbackButtonsElement( + action_id="feedback", + positive_button=FeedbackButtonObject( + text="Good Response", + accessibility_label="Submit positive feedback on this response", + value="good-feedback", + ), + negative_button=FeedbackButtonObject( + text="Bad Response", + accessibility_label="Submit negative feedback on this response", + value="bad-feedback", + ), + ) + ] + ) + ] + return blocks + +@app.message() +def handle_message(message, client): + # ... previous streaming code ... + + # Stop the stream and add interactive elements + feedback_block = create_feedback_block() + client.chat_stopStream( + channel=channel_id, + ts=stream_ts, + blocks=feedback_block + ) +``` + +See [Formatting messages with Block Kit](#block-kit) below for more details on using Block Kit with messages. + ## Formatting messages with Block Kit {#block-kit} Messages posted from apps can contain more than just text; they can also include full user interfaces composed of blocks using [Block Kit](/block-kit). From fd83b2703603de95b69859f59070b7a5bbbcf069 Mon Sep 17 00:00:00 2001 From: Luke Russell <31357343+lukegalbraithrussell@users.noreply.github.com> Date: Fri, 3 Oct 2025 16:08:01 -0700 Subject: [PATCH 20/21] docs: fixes formatting error for ai apps docs (#1765) --- docs/english/web.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/english/web.md b/docs/english/web.md index 0b689c530..49d6c5871 100644 --- a/docs/english/web.md +++ b/docs/english/web.md @@ -61,7 +61,7 @@ You can have your app's messages stream in to replicate conventional AI chatbot * [`chat_appendStream`](/reference/methods/chat.appendstream) * [`chat_stopStream`](/reference/methods/chat.stopstream) -:::tip [The Python Slack SDK provides a [`chat_stream()`](https://docs.slack.dev/tools/python-slack-sdk/reference/web/client.html#slack_sdk.web.client.WebClient.chat_stream) helper utility to streamline calling these methods.] +:::tip[The Python Slack SDK provides a [`chat_stream()`](https://docs.slack.dev/tools/python-slack-sdk/reference/web/client.html#slack_sdk.web.client.WebClient.chat_stream) helper utility to streamline calling these methods.] See the [_Streaming messages_](/tools/bolt-python/concepts/message-sending#streaming-messages) section of the Bolt for Python docs for implementation instructions. From 55a943e36ece4da4cf9191b859dc5692fbce9016 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Mon, 6 Oct 2025 15:41:30 -0700 Subject: [PATCH 21/21] revert: undo development versions before merging to main --- slack_sdk/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slack_sdk/version.py b/slack_sdk/version.py index f56594ea1..a38bbbbbf 100644 --- a/slack_sdk/version.py +++ b/slack_sdk/version.py @@ -1,3 +1,3 @@ """Check the latest version at https://pypi.org/project/slack-sdk/""" -__version__ = "3.36.0.dev7" +__version__ = "3.36.0"