thread_ts: str,
recipient_team_id: Optional[str] = None,
recipient_user_id: Optional[str] = None,
+ task_display_mode: Optional[str] = None,
**kwargs,
) -> ChatStream:
"""Stream markdown text into a conversation.
@@ -10443,6 +10737,8 @@
Methods
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.
+ task_display_mode: Specifies how tasks are displayed in the message. A "timeline" displays individual tasks
+ with text and "plan" displays all tasks together.
**kwargs: Additional arguments passed to the underlying API calls.
Returns:
@@ -10468,6 +10764,7 @@
if callable(method) and hasattr(method, "validator"):
method()
+ def get_object_attribute(self, key: str):
+ return getattr(self, key, None)
+
def get_non_null_attributes(self) -> dict:
"""
Construct a dictionary out of non-null keys (from attributes property)
@@ -136,7 +139,7 @@
Ancestors
return value
def is_not_empty(self, key: str) -> bool:
- value = getattr(self, key, None)
+ value = self.get_object_attribute(key)
if value is None:
return False
@@ -154,7 +157,9 @@
Ancestors
return value is not None
return {
- key: to_dict_compatible(getattr(self, key, None)) for key in sorted(self.attributes) if is_not_empty(self, key)
+ key: to_dict_compatible(value=self.get_object_attribute(key))
+ for key in sorted(self.attributes)
+ if is_not_empty(self, key)
}
def to_dict(self, *args) -> dict:
@@ -207,8 +212,42 @@
return value
def is_not_empty(self, key: str) -> bool:
- value = getattr(self, key, None)
+ value = self.get_object_attribute(key)
if value is None:
return False
@@ -275,12 +314,27 @@
Methods
return value is not None
return {
- key: to_dict_compatible(getattr(self, key, None)) for key in sorted(self.attributes) if is_not_empty(self, key)
+ key: to_dict_compatible(value=self.get_object_attribute(key))
+ for key in sorted(self.attributes)
+ if is_not_empty(self, key)
}
Construct a dictionary out of non-null keys (from attributes property)
present on this object
@staticmethod
+def direct_from_string(text: str) -> Dict[str, Any]:
+ """Transforms a string into the required object shape to act as a RawTextObject"""
+ return RawTextObject.from_str(text).to_dict()
+
+
Transforms a string into the required object shape to act as a RawTextObject
class PlanBlock(Block):
+ type = "plan"
+
+ @property
+ def attributes(self) -> Set[str]: # type: ignore[override]
+ return super().attributes.union(
+ {
+ "title",
+ "tasks",
+ }
+ )
+
+ def __init__(
+ self,
+ *,
+ title: str,
+ tasks: Optional[Sequence[Union[Dict, TaskCardBlock]]] = None,
+ block_id: Optional[str] = None,
+ **others: dict,
+ ):
+ """Displays a collection of related tasks.
+ https://docs.slack.dev/reference/block-kit/blocks/plan-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.
+ title (required): Title of the plan in plain text
+ tasks: A sequence of task card blocks. Each task represents a single action within the plan.
+ """
+ super().__init__(type=self.type, block_id=block_id)
+ show_unknown_key_warning(self, others)
+
+ self.title = title
+ self.tasks = tasks
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.
+
title : required
+
Title of the plan in plain text
+
tasks
+
A sequence of task card blocks. Each task represents a single action within the plan.
class TableBlock(Block):
+ type = "table"
+
+ @property
+ def attributes(self) -> Set[str]: # type: ignore[override]
+ return super().attributes.union({"rows", "column_settings"})
+
+ def __init__(
+ self,
+ *,
+ rows: Sequence[Sequence[Dict[str, Any]]],
+ column_settings: Optional[Sequence[Optional[Dict[str, Any]]]] = None,
+ block_id: Optional[str] = None,
+ **others: dict,
+ ):
+ """Displays structured information in a table.
+ https://docs.slack.dev/reference/block-kit/blocks/table-block
+
+ Args:
+ rows (required): An array consisting of table rows. Maximum 100 rows.
+ Each row object is an array with a max of 20 table cells.
+ Table cells can have a type of raw_text or rich_text.
+ column_settings: An array describing column behavior. If there are fewer items in the column_settings array
+ than there are columns in the table, then the items in the the column_settings array will describe
+ the same number of columns in the table as there are in the array itself.
+ Any additional columns will have the default behavior. Maximum 20 items.
+ See below for column settings schema.
+ block_id: A unique identifier for a block. If not specified, a block_id will be generated.
+ You can use this block_id when you receive an interaction payload to identify the source of the action.
+ 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.rows = rows
+ self.column_settings = column_settings
+
+ @JsonValidator("rows attribute must be specified")
+ def _validate_rows(self):
+ return self.rows is not None and len(self.rows) > 0
An array consisting of table rows. Maximum 100 rows.
+Each row object is an array with a max of 20 table cells.
+Table cells can have a type of raw_text or rich_text.
+
column_settings
+
An array describing column behavior. If there are fewer items in the column_settings array
+than there are columns in the table, then the items in the the column_settings array will describe
+the same number of columns in the table as there are in the array itself.
+Any additional columns will have the default behavior. Maximum 20 items.
+See below for column settings schema.
+
block_id
+
A unique identifier for a block. If not specified, a block_id will be generated.
+You can use this block_id when you receive an interaction payload to identify the source of the action.
+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.
class TaskCardBlock(Block):
+ type = "task_card"
+
+ @property
+ def attributes(self) -> Set[str]: # type: ignore[override]
+ return super().attributes.union(
+ {
+ "task_id",
+ "title",
+ "details",
+ "output",
+ "sources",
+ "status",
+ }
+ )
+
+ def __init__(
+ self,
+ *,
+ task_id: str,
+ title: str,
+ details: Optional[Union[RichTextBlock, dict]] = None,
+ output: Optional[Union[RichTextBlock, dict]] = None,
+ sources: Optional[Sequence[Union[UrlSourceElement, dict]]] = None,
+ status: str, # pending, in_progress, complete, error
+ block_id: Optional[str] = None,
+ **others: dict,
+ ):
+ """Displays a single task, representing a single action.
+ https://docs.slack.dev/reference/block-kit/blocks/task-card-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.
+ task_id (required): ID for the task
+ title (required): Title of the task in plain text
+ details: Details of the task in the form of a single "rich_text" entity.
+ output: Output of the task in the form of a single "rich_text" entity.
+ sources: Array of URL source elements used to generate a response.
+ status: The state of a task. Either "pending", "in_progress", "complete", or "error".
+ """
+ super().__init__(type=self.type, block_id=block_id)
+ show_unknown_key_warning(self, others)
+
+ self.task_id = task_id
+ self.title = title
+ self.details = details
+ self.output = output
+ self.sources = sources
+ self.status = status
+
+ @JsonValidator("status must be an expected value (pending, in_progress, complete, or error)")
+ def _validate_rows(self):
+ return self.status in ["pending", "in_progress", "complete", "error"]
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.
+
task_id : required
+
ID for the task
+
title : required
+
Title of the task in plain text
+
details
+
Details of the task in the form of a single "rich_text" entity.
+
output
+
Output of the task in the form of a single "rich_text" entity.
+
sources
+
Array of URL source elements used to generate a response.
+
status
+
The state of a task. Either "pending", "in_progress", "complete", or "error".
class PlanBlock(Block):
+ type = "plan"
+
+ @property
+ def attributes(self) -> Set[str]: # type: ignore[override]
+ return super().attributes.union(
+ {
+ "title",
+ "tasks",
+ }
+ )
+
+ def __init__(
+ self,
+ *,
+ title: str,
+ tasks: Optional[Sequence[Union[Dict, TaskCardBlock]]] = None,
+ block_id: Optional[str] = None,
+ **others: dict,
+ ):
+ """Displays a collection of related tasks.
+ https://docs.slack.dev/reference/block-kit/blocks/plan-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.
+ title (required): Title of the plan in plain text
+ tasks: A sequence of task card blocks. Each task represents a single action within the plan.
+ """
+ super().__init__(type=self.type, block_id=block_id)
+ show_unknown_key_warning(self, others)
+
+ self.title = title
+ self.tasks = tasks
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.
+
title : required
+
Title of the plan in plain text
+
tasks
+
A sequence of task card blocks. Each task represents a single action within the plan.
@staticmethod
+def direct_from_string(text: str) -> Dict[str, Any]:
+ """Transforms a string into the required object shape to act as a RawTextObject"""
+ return RawTextObject.from_str(text).to_dict()
+
+
Transforms a string into the required object shape to act as a RawTextObject
class TableBlock(Block):
+ type = "table"
+
+ @property
+ def attributes(self) -> Set[str]: # type: ignore[override]
+ return super().attributes.union({"rows", "column_settings"})
+
+ def __init__(
+ self,
+ *,
+ rows: Sequence[Sequence[Dict[str, Any]]],
+ column_settings: Optional[Sequence[Optional[Dict[str, Any]]]] = None,
+ block_id: Optional[str] = None,
+ **others: dict,
+ ):
+ """Displays structured information in a table.
+ https://docs.slack.dev/reference/block-kit/blocks/table-block
+
+ Args:
+ rows (required): An array consisting of table rows. Maximum 100 rows.
+ Each row object is an array with a max of 20 table cells.
+ Table cells can have a type of raw_text or rich_text.
+ column_settings: An array describing column behavior. If there are fewer items in the column_settings array
+ than there are columns in the table, then the items in the the column_settings array will describe
+ the same number of columns in the table as there are in the array itself.
+ Any additional columns will have the default behavior. Maximum 20 items.
+ See below for column settings schema.
+ block_id: A unique identifier for a block. If not specified, a block_id will be generated.
+ You can use this block_id when you receive an interaction payload to identify the source of the action.
+ 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.rows = rows
+ self.column_settings = column_settings
+
+ @JsonValidator("rows attribute must be specified")
+ def _validate_rows(self):
+ return self.rows is not None and len(self.rows) > 0
An array consisting of table rows. Maximum 100 rows.
+Each row object is an array with a max of 20 table cells.
+Table cells can have a type of raw_text or rich_text.
+
column_settings
+
An array describing column behavior. If there are fewer items in the column_settings array
+than there are columns in the table, then the items in the the column_settings array will describe
+the same number of columns in the table as there are in the array itself.
+Any additional columns will have the default behavior. Maximum 20 items.
+See below for column settings schema.
+
block_id
+
A unique identifier for a block. If not specified, a block_id will be generated.
+You can use this block_id when you receive an interaction payload to identify the source of the action.
+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.
class TaskCardBlock(Block):
+ type = "task_card"
+
+ @property
+ def attributes(self) -> Set[str]: # type: ignore[override]
+ return super().attributes.union(
+ {
+ "task_id",
+ "title",
+ "details",
+ "output",
+ "sources",
+ "status",
+ }
+ )
+
+ def __init__(
+ self,
+ *,
+ task_id: str,
+ title: str,
+ details: Optional[Union[RichTextBlock, dict]] = None,
+ output: Optional[Union[RichTextBlock, dict]] = None,
+ sources: Optional[Sequence[Union[UrlSourceElement, dict]]] = None,
+ status: str, # pending, in_progress, complete, error
+ block_id: Optional[str] = None,
+ **others: dict,
+ ):
+ """Displays a single task, representing a single action.
+ https://docs.slack.dev/reference/block-kit/blocks/task-card-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.
+ task_id (required): ID for the task
+ title (required): Title of the task in plain text
+ details: Details of the task in the form of a single "rich_text" entity.
+ output: Output of the task in the form of a single "rich_text" entity.
+ sources: Array of URL source elements used to generate a response.
+ status: The state of a task. Either "pending", "in_progress", "complete", or "error".
+ """
+ super().__init__(type=self.type, block_id=block_id)
+ show_unknown_key_warning(self, others)
+
+ self.task_id = task_id
+ self.title = title
+ self.details = details
+ self.output = output
+ self.sources = sources
+ self.status = status
+
+ @JsonValidator("status must be an expected value (pending, in_progress, complete, or error)")
+ def _validate_rows(self):
+ return self.status in ["pending", "in_progress", "complete", "error"]
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.
+
task_id : required
+
ID for the task
+
title : required
+
Title of the task in plain text
+
details
+
Details of the task in the form of a single "rich_text" entity.
+
output
+
Output of the task in the form of a single "rich_text" entity.
+
sources
+
Array of URL source elements used to generate a response.
+
status
+
The state of a task. Either "pending", "in_progress", "complete", or "error".
if callable(method) and hasattr(method, "validator"):
method()
+ def get_object_attribute(self, key: str):
+ return getattr(self, key, None)
+
def get_non_null_attributes(self) -> dict:
"""
Construct a dictionary out of non-null keys (from attributes property)
@@ -240,7 +243,7 @@
Ancestors
return value
def is_not_empty(self, key: str) -> bool:
- value = getattr(self, key, None)
+ value = self.get_object_attribute(key)
if value is None:
return False
@@ -258,7 +261,9 @@
Ancestors
return value is not None
return {
- key: to_dict_compatible(getattr(self, key, None)) for key in sorted(self.attributes) if is_not_empty(self, key)
+ key: to_dict_compatible(value=self.get_object_attribute(key))
+ for key in sorted(self.attributes)
+ if is_not_empty(self, key)
}
def to_dict(self, *args) -> dict:
@@ -311,8 +316,42 @@
return value
def is_not_empty(self, key: str) -> bool:
- value = getattr(self, key, None)
+ value = self.get_object_attribute(key)
if value is None:
return False
@@ -379,12 +418,27 @@
Methods
return value is not None
return {
- key: to_dict_compatible(getattr(self, key, None)) for key in sorted(self.attributes) if is_not_empty(self, key)
+ key: to_dict_compatible(value=self.get_object_attribute(key))
+ for key in sorted(self.attributes)
+ if is_not_empty(self, key)
}
Construct a dictionary out of non-null keys (from attributes property)
present on this object
@property
+def entity_attributes(self) -> Union[Dict[str, Any], EntityAttributes]:
+ """Get the entity attributes data.
+
+ Note: Use this property to access the attributes data. The class-level
+ 'attributes' is reserved for the JSON serialization schema.
+ """
+ return self._entity_attributes
+
+
Get the entity attributes data.
+
Note: Use this property to access the attributes data. The class-level
+'attributes' is reserved for the JSON serialization schema.
def normalize_datetime_for_db(dt: Optional[datetime]) -> Optional[datetime]:
+ """
+ Normalize timezone-aware datetime to naive UTC datetime for database storage.
+
+ Ensures compatibility with existing databases using TIMESTAMP WITHOUT TIME ZONE.
+ SQLAlchemy DateTime columns without timezone=True create naive timestamp columns
+ in databases like PostgreSQL. This function strips timezone information from
+ timezone-aware datetimes (which are already in UTC) to enable safe comparisons.
+
+ Args:
+ dt: A timezone-aware or naive datetime object, or None
+
+ Returns:
+ A naive datetime in UTC, or None if input is None
+
+ Example:
+ >>> from datetime import datetime, timezone
+ >>> aware_dt = datetime(2024, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
+ >>> naive_dt = normalize_datetime_for_db(aware_dt)
+ >>> naive_dt.tzinfo is None
+ True
+ """
+ if dt is None:
+ return None
+ if dt.tzinfo is not None:
+ return dt.replace(tzinfo=None)
+ return dt
+
+
Normalize timezone-aware datetime to naive UTC datetime for database storage.
+
Ensures compatibility with existing databases using TIMESTAMP WITHOUT TIME ZONE.
+SQLAlchemy DateTime columns without timezone=True create naive timestamp columns
+in databases like PostgreSQL. This function strips timezone information from
+timezone-aware datetimes (which are already in UTC) to enable safe comparisons.
+
Args
+
+
dt
+
A timezone-aware or naive datetime object, or None
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.
+ task_display_mode: Specifies how tasks are displayed in the message. A "timeline" displays individual tasks
+ with text and "plan" displays all tasks together.
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.
@@ -99,6 +102,7 @@
is stopped this method cannot be called.
Args:
+ chunks: An array of streaming chunks. Chunks can be markdown text, plan, or task update chunks.
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.
@@ -145,9 +151,10 @@
Classes
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)
+ if markdown_text is not None:
+ self._buffer += markdown_text
+ if len(self._buffer) >= self._buffer_size or chunks is not None:
+ return await self._flush_buffer(chunks=chunks, **kwargs)
details = {
"buffer_length": len(self._buffer),
"buffer_size": self._buffer_size,
@@ -163,6 +170,7 @@
Args:
blocks: A list of blocks that will be rendered at the bottom of the finalized message.
+ chunks: An array of streaming chunks. Chunks can be markdown text, plan, or task update chunks.
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
@@ -211,26 +220,36 @@
Classes
raise e.SlackRequestError("Failed to stop stream: stream not started")
self._stream_ts = str(response["ts"])
self._state = "in_progress"
+ flushings: List[Union[Dict, Chunk]] = []
+ if len(self._buffer) != 0:
+ flushings.append(MarkdownTextChunk(text=self._buffer))
+ if chunks is not None:
+ flushings.extend(chunks)
response = await self._client.chat_stopStream(
token=self._token,
channel=self._stream_args["channel"],
ts=self._stream_ts,
blocks=blocks,
- markdown_text=self._buffer,
+ chunks=flushings,
metadata=metadata,
**kwargs,
)
self._state = "completed"
return response
- async def _flush_buffer(self, **kwargs) -> AsyncSlackResponse:
- """Flush the internal buffer by making appropriate API calls."""
+ async def _flush_buffer(self, chunks: Optional[Sequence[Union[Dict, Chunk]]] = None, **kwargs) -> AsyncSlackResponse:
+ """Flush the internal buffer with chunks by making appropriate API calls."""
+ chunks_to_flush: List[Union[Dict, Chunk]] = []
+ if len(self._buffer) != 0:
+ chunks_to_flush.append(MarkdownTextChunk(text=self._buffer))
+ if chunks is not None:
+ chunks_to_flush.extend(chunks)
if not self._stream_ts:
response = await self._client.chat_startStream(
**self._stream_args,
token=self._token,
**kwargs,
- markdown_text=self._buffer,
+ chunks=chunks_to_flush,
)
self._stream_ts = response.get("ts")
self._state = "in_progress"
@@ -240,7 +259,7 @@
The encoded ID of the user to receive the streaming text. Required when streaming to channels.
+
task_display_mode
+
Specifies how tasks are displayed in the message. A "timeline" displays individual tasks
+with text and "plan" displays all tasks together.
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.
is stopped this method cannot be called.
Args:
+ chunks: An array of streaming chunks. Chunks can be markdown text, plan, or task update chunks.
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.
@@ -321,9 +345,10 @@
Methods
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)
+ if markdown_text is not None:
+ self._buffer += markdown_text
+ if len(self._buffer) >= self._buffer_size or chunks is not None:
+ return await self._flush_buffer(chunks=chunks, **kwargs)
details = {
"buffer_length": len(self._buffer),
"buffer_size": self._buffer_size,
@@ -340,6 +365,8 @@
Methods
is stopped this method cannot be called.
Args
+
chunks
+
An array of streaming chunks. Chunks can be markdown text, plan, or task update chunks.
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.
Args:
blocks: A list of blocks that will be rendered at the bottom of the finalized message.
+ chunks: An array of streaming chunks. Chunks can be markdown text, plan, or task update chunks.
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
@@ -425,12 +454,17 @@
Example
raise e.SlackRequestError("Failed to stop stream: stream not started")
self._stream_ts = str(response["ts"])
self._state = "in_progress"
+ flushings: List[Union[Dict, Chunk]] = []
+ if len(self._buffer) != 0:
+ flushings.append(MarkdownTextChunk(text=self._buffer))
+ if chunks is not None:
+ flushings.extend(chunks)
response = await self._client.chat_stopStream(
token=self._token,
channel=self._stream_args["channel"],
ts=self._stream_ts,
blocks=blocks,
- markdown_text=self._buffer,
+ chunks=flushings,
metadata=metadata,
**kwargs,
)
@@ -442,6 +476,8 @@
Args
blocks
A list of blocks that will be rendered at the bottom of the finalized message.
+
chunks
+
An array of streaming chunks. Chunks can be markdown text, plan, or task update chunks.
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.
thread_ts: str,
recipient_team_id: Optional[str] = None,
recipient_user_id: Optional[str] = None,
+ task_display_mode: Optional[str] = None,
**kwargs,
) -> AsyncChatStream:
"""Stream markdown text into a conversation.
@@ -2982,6 +2993,8 @@
Classes
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.
+ task_display_mode: Specifies how tasks are displayed in the message. A "timeline" displays individual tasks
+ with text and "plan" displays all tasks together.
**kwargs: Additional arguments passed to the underlying API calls.
Returns:
@@ -3007,6 +3020,7 @@
thread_ts: str,
recipient_team_id: Optional[str] = None,
recipient_user_id: Optional[str] = None,
+ task_display_mode: Optional[str] = None,
**kwargs,
) -> AsyncChatStream:
"""Stream markdown text into a conversation.
@@ -10339,6 +10633,8 @@
Methods
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.
+ task_display_mode: Specifies how tasks are displayed in the message. A "timeline" displays individual tasks
+ with text and "plan" displays all tasks together.
**kwargs: Additional arguments passed to the underlying API calls.
Returns:
@@ -10364,6 +10660,7 @@
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.
+ task_display_mode: Specifies how tasks are displayed in the message. A "timeline" displays individual tasks
+ with text and "plan" displays all tasks together.
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.
@@ -99,6 +102,7 @@
is stopped this method cannot be called.
Args:
+ chunks: An array of streaming chunks. Chunks can be markdown text, plan, or task update chunks.
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.
@@ -145,9 +151,10 @@
Classes
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)
+ if markdown_text is not None:
+ self._buffer += markdown_text
+ if len(self._buffer) >= self._buffer_size or chunks is not None:
+ return self._flush_buffer(chunks=chunks, **kwargs)
details = {
"buffer_length": len(self._buffer),
"buffer_size": self._buffer_size,
@@ -163,6 +170,7 @@
Args:
blocks: A list of blocks that will be rendered at the bottom of the finalized message.
+ chunks: An array of streaming chunks. Chunks can be markdown text, plan, or task update chunks.
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
@@ -211,26 +220,36 @@
Classes
raise e.SlackRequestError("Failed to stop stream: stream not started")
self._stream_ts = str(response["ts"])
self._state = "in_progress"
+ flushings: List[Union[Dict, Chunk]] = []
+ if len(self._buffer) != 0:
+ flushings.append(MarkdownTextChunk(text=self._buffer))
+ if chunks is not None:
+ flushings.extend(chunks)
response = self._client.chat_stopStream(
token=self._token,
channel=self._stream_args["channel"],
ts=self._stream_ts,
blocks=blocks,
- markdown_text=self._buffer,
+ chunks=flushings,
metadata=metadata,
**kwargs,
)
self._state = "completed"
return response
- def _flush_buffer(self, **kwargs) -> SlackResponse:
- """Flush the internal buffer by making appropriate API calls."""
+ def _flush_buffer(self, chunks: Optional[Sequence[Union[Dict, Chunk]]] = None, **kwargs) -> SlackResponse:
+ """Flush the internal buffer with chunks by making appropriate API calls."""
+ chunks_to_flush: List[Union[Dict, Chunk]] = []
+ if len(self._buffer) != 0:
+ chunks_to_flush.append(MarkdownTextChunk(text=self._buffer))
+ if chunks is not None:
+ chunks_to_flush.extend(chunks)
if not self._stream_ts:
response = self._client.chat_startStream(
**self._stream_args,
token=self._token,
**kwargs,
- markdown_text=self._buffer,
+ chunks=chunks_to_flush,
)
self._stream_ts = response.get("ts")
self._state = "in_progress"
@@ -240,7 +259,7 @@
The encoded ID of the user to receive the streaming text. Required when streaming to channels.
+
task_display_mode
+
Specifies how tasks are displayed in the message. A "timeline" displays individual tasks
+with text and "plan" displays all tasks together.
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.
is stopped this method cannot be called.
Args:
+ chunks: An array of streaming chunks. Chunks can be markdown text, plan, or task update chunks.
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.
@@ -321,9 +345,10 @@
Methods
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)
+ if markdown_text is not None:
+ self._buffer += markdown_text
+ if len(self._buffer) >= self._buffer_size or chunks is not None:
+ return self._flush_buffer(chunks=chunks, **kwargs)
details = {
"buffer_length": len(self._buffer),
"buffer_size": self._buffer_size,
@@ -340,6 +365,8 @@
Methods
is stopped this method cannot be called.
Args
+
chunks
+
An array of streaming chunks. Chunks can be markdown text, plan, or task update chunks.
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.
Args:
blocks: A list of blocks that will be rendered at the bottom of the finalized message.
+ chunks: An array of streaming chunks. Chunks can be markdown text, plan, or task update chunks.
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
@@ -425,12 +454,17 @@
Example
raise e.SlackRequestError("Failed to stop stream: stream not started")
self._stream_ts = str(response["ts"])
self._state = "in_progress"
+ flushings: List[Union[Dict, Chunk]] = []
+ if len(self._buffer) != 0:
+ flushings.append(MarkdownTextChunk(text=self._buffer))
+ if chunks is not None:
+ flushings.extend(chunks)
response = self._client.chat_stopStream(
token=self._token,
channel=self._stream_args["channel"],
ts=self._stream_ts,
blocks=blocks,
- markdown_text=self._buffer,
+ chunks=flushings,
metadata=metadata,
**kwargs,
)
@@ -442,6 +476,8 @@
Args
blocks
A list of blocks that will be rendered at the bottom of the finalized message.
+
chunks
+
An array of streaming chunks. Chunks can be markdown text, plan, or task update chunks.
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.
thread_ts: str,
recipient_team_id: Optional[str] = None,
recipient_user_id: Optional[str] = None,
+ task_display_mode: Optional[str] = None,
**kwargs,
) -> ChatStream:
"""Stream markdown text into a conversation.
@@ -2982,6 +2993,8 @@
Classes
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.
+ task_display_mode: Specifies how tasks are displayed in the message. A "timeline" displays individual tasks
+ with text and "plan" displays all tasks together.
**kwargs: Additional arguments passed to the underlying API calls.
Returns:
@@ -3007,6 +3020,7 @@
thread_ts: str,
recipient_team_id: Optional[str] = None,
recipient_user_id: Optional[str] = None,
+ task_display_mode: Optional[str] = None,
**kwargs,
) -> ChatStream:
"""Stream markdown text into a conversation.
@@ -10339,6 +10633,8 @@
Methods
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.
+ task_display_mode: Specifies how tasks are displayed in the message. A "timeline" displays individual tasks
+ with text and "plan" displays all tasks together.
**kwargs: Additional arguments passed to the underlying API calls.
Returns:
@@ -10364,6 +10660,7 @@
thread_ts: str,
recipient_team_id: Optional[str] = None,
recipient_user_id: Optional[str] = None,
+ task_display_mode: Optional[str] = None,
**kwargs,
) -> ChatStream:
"""Stream markdown text into a conversation.
@@ -3351,6 +3362,8 @@
Raises
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.
+ task_display_mode: Specifies how tasks are displayed in the message. A "timeline" displays individual tasks
+ with text and "plan" displays all tasks together.
**kwargs: Additional arguments passed to the underlying API calls.
Returns:
@@ -3376,6 +3389,7 @@
thread_ts: str,
recipient_team_id: Optional[str] = None,
recipient_user_id: Optional[str] = None,
+ task_display_mode: Optional[str] = None,
**kwargs,
) -> ChatStream:
"""Stream markdown text into a conversation.
@@ -10708,6 +11002,8 @@
Methods
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.
+ task_display_mode: Specifies how tasks are displayed in the message. A "timeline" displays individual tasks
+ with text and "plan" displays all tasks together.
**kwargs: Additional arguments passed to the underlying API calls.
Returns:
@@ -10733,6 +11029,7 @@