Skip to content

feat: accept chunks as arguments to chat.{start,append,stop}Stream methods - #1806

Merged
zimeg merged 4 commits into
feat-ai-apps-thinking-stepsfrom
zimeg-feat-ai-apps-chunks
Jan 16, 2026
Merged

feat: accept chunks as arguments to chat.{start,append,stop}Stream methods#1806
zimeg merged 4 commits into
feat-ai-apps-thinking-stepsfrom
zimeg-feat-ai-apps-chunks

Conversation

@zimeg

Copy link
Copy Markdown
Member

Summary

This PR introduces the chunks argument to the following methods:

⚠️ This feature is experimental at the moment!

Testing

The following code snippet might be interesting to experiment with:

importtime
...
streamer=client.chat_startStream(
channel=channel_id,
recipient_team_id=team_id,
recipient_user_id=user_id,
thread_ts=thread_ts,
chunks=[
MarkdownTextChunk(text="**onwards processing**"),
TaskUpdateChunk(
id="12",
title="counting bytes...",
status="in_progress",
),
],
)
time.sleep(4)
client.chat_appendStream(
channel=channel_id,
ts=streamer.get("ts"),
markdown_text="",
chunks=[
TaskUpdateChunk(
id="12",
title="adding numbers...",
status="in_progress",
details="sums have increased",
)
],
)
time.sleep(4)
client.chat_stopStream(
channel=channel_id,
ts=streamer.get("ts"),
chunks=[
TaskUpdateChunk(
id="12",
title="solved equation!",
status="complete",
sources=[
URLSource(
url="https://oeis.org",
text="The On-Line Encyclopedia of Integer Sequences (OEIS)",
),
],
),
MarkdownTextChunk(text="that computes."),
],
)

Category

  • slack_sdk.web.WebClient (sync/async) (Web API client)
  • slack_sdk.models (UI component builders)
  • /docs (Documents)
  • tests/integration_tests (Automated tests for this library)

Notes

  • Planning to add tests alongside these methods soon!
  • Unsure if these are the best naming for "models" and I'm open to suggestions!

Requirements

  • I've read and understood the Contributing Guidelines and have done my best effort to follow them.
  • I've read and agree to the Code of Conduct.
  • I've run python3 -m venv .venv && source .venv/bin/activate && ./scripts/run_validation.sh after making the changes.

@zimegzimeg self-assigned this Dec 11, 2025
@zimegzimeg added enhancement M-T: A feature request for new functionality semver:minor web-client Version: 3x labels Dec 11, 2025
@codecov

codecovBot commented Dec 11, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.97872% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.90%. Comparing base (96c0f84) to head (1fb7355).
⚠️ Report is 1 commits behind head on feat-ai-apps-thinking-steps.
✅ All tests successful. No failed tests found.

Files with missing linesPatch %Lines
slack_sdk/models/messages/chunk.py77.77%16 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## feat-ai-apps-thinking-steps #1806 +/- ##
===============================================================
- Coverage 83.91% 83.90% -0.01% 
===============================================================
Files 115 116 +1 Lines 13080 13168 +88 ===============================================================
+ Hits 10976 11049 +73 - Misses 2104 2119 +15 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@srtaalejsrtaalej left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm! except does the helper function not have to change the way it updates the buffer now that we can use chunks instead of markdown?

@zimeg

Copy link
Copy Markdown
MemberAuthor

@srtaalej Thanks for taking a look! I separated changes to the chat_stream helper in #1809 for more clear review, but some changes might've been better suited for here - perhaps optional markdown text...

@zimegzimeg mentioned this pull request Jan 13, 2026
6 tasks

@zimegzimeg left a comment

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👾 Leaving a few updates from the future! These are refactors made in a "stacked" branch. Please do let me know if rebasing is preferred though-

Comment on lines +70 to +105
class URLSource(JsonObject):
type = "url"

@property
def attributes(self) -> Set[str]:
return super().attributes.union(
{
"url",
"text",
"icon_url",
}
)

def __init__(
self,
*,
url: str,
text: str,
icon_url: Optional[str] = None,
**others: Dict,
):
show_unknown_key_warning(self, others)
self._url = url
self._text = text
self._icon_url = icon_url

def to_dict(self) -> Dict[str, Any]:
self.validate_json()
json: Dict[str, Union[str, Dict]] = {
"type": self.type,
"url": self._url,
"text": self._text,
}
if self._icon_url:
json["icon_url"] = self._icon_url
return json

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📣 note: In 6073ffe of #1819 this is moved into the block elements class because it can be used in standalone messages - not just chunks.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧮 note: It's also changed from "URL" to "Url" to match similar elements!

Comment on lines +147 to +155
if sources is not None:
self.sources = []
for src in sources:
if isinstance(src, Dict):
self.sources.append(src)
elif isinstance(src, URLSource):
self.sources.append(src.to_dict())
else:
raise SlackObjectFormationError(f"Unsupported type for source in task update chunk: {type(src)}")

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🪓 note: This is simplified alongside the changes of #1819 as well!

@zimeg
zimeg marked this pull request as ready for review January 14, 2026 20:03
@zimeg
zimeg requested a review from a team as a code ownerJanuary 14, 2026 20:03

@mwbrooksmwbrooks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ The code looks good and it works well for me!

🧪 Testing locally works well using your sample app. In case others want to check, I'll include my listeners/assistant/message.py from the sample app.

bolt-python-assistant-template/listeners/assistant/message.py:
fromloggingimportLoggerfromtypingimportDict, Listfromslack_boltimportBoltContext, Say, SetStatusfromslack_sdkimportWebClientfromai.llm_callerimportcall_llmfrom ..views.feedback_blockimportcreate_feedback_blockimporttimefromslack_sdk.models.messages.chunkimportMarkdownTextChunk, TaskUpdateChunk, URLSourcedefmessage(
client: WebClient,
context: BoltContext,
logger: Logger,
payload: dict,
say: Say,
set_status: SetStatus,
):
""" Handles when users send messages or select a prompt in an assistant thread and generate AI responses: Args: client: Slack WebClient for making API calls context: Bolt context containing channel and thread information logger: Logger instance for error tracking payload: Event payload with message details (channel, user, text, etc.) say: Function to send messages to the thread set_status: Function to update the assistant's status """try:
channel_id=payload["channel"]
team_id=context.team_idthread_ts=payload["thread_ts"]
user_id=context.user_idset_status(
status="thinking...",
loading_messages=[
"Teaching the hamsters to type faster…",
"Untangling the internet cables…",
"Consulting the office goldfish…",
"Polishing up the response just for you…",
"Convincing the AI to stop overthinking…",
],
)
replies=client.conversations_replies(
channel=context.channel_id,
ts=context.thread_ts,
oldest=context.thread_ts,
limit=10,
)
messages_in_thread: List[Dict[str, str]] = []
formessageinreplies["messages"]:
role="user"ifmessage.get("bot_id") isNoneelse"assistant"messages_in_thread.append({"role": role, "content": message["text"]})
returned_message=call_llm(messages_in_thread)
streamer=client.chat_startStream(
channel=channel_id,
recipient_team_id=team_id,
recipient_user_id=user_id,
thread_ts=thread_ts,
chunks=[
MarkdownTextChunk(text="**onwards processing**"),
TaskUpdateChunk(
id="12",
title="counting bytes...",
status="in_progress",
),
],
)
time.sleep(4)
client.chat_appendStream(
channel=channel_id,
ts=streamer.get("ts"),
markdown_text="",
chunks=[
TaskUpdateChunk(
id="12",
title="adding numbers...",
status="in_progress",
details="sums have increased",
)
],
)
time.sleep(4)
client.chat_stopStream(
channel=channel_id,
ts=streamer.get("ts"),
chunks=[
TaskUpdateChunk(
id="12",
title="solved equation!",
status="complete",
sources=[
URLSource(
url="https://oeis.org",
text="The On-Line Encyclopedia of Integer Sequences (OEIS)",
),
],
),
MarkdownTextChunk(text="that computes."),
],
)
exceptExceptionase:
logger.exception(f"Failed to handle a user message event: {e}")
say(f":warning: Something went wrong! ({e})")

@WilliamBergaminWilliamBergamin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work ✅

Left a few comments, I don't think any one them are blocking 🚀

*,
id: str,
title: str,
status: str, # "pending", "in_progress", "complete", "error"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: if you find this valuable I think you could use some sort of Enum instead of raw strings for the status but I'm not sure how this ill play out in a JsonObject 🤔

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@WilliamBergamin Ohh nice I forgot this feature is supported! I'll save this for a follow up PR as well for ongoing testing 🤖

channel: str,
ts: str,
markdown_text: str,
chunks: Optional[Sequence[Union[Dict, Chunk]]] = None,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the above markdown_text be made optional as well here?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@WilliamBergamin Nice catch - yes! In #1809 it's updated and we'll squash these together next before a prerelease 📠

@zimeg

Copy link
Copy Markdown
MemberAuthor

@srtaalej@mwbrooks@WilliamBergamin Thanks all for taking a look and sharing amazing feedback! 💌

I've taken note to prefer optionals and enums for certain arguments but am saving this for a follow up PR at this time to avoid rebasing branches!

@zimeg
zimeg merged commit 1c84f7f into feat-ai-apps-thinking-stepsJan 16, 2026
16 checks passed
@zimeg
zimeg deleted the zimeg-feat-ai-apps-chunks branch January 16, 2026 23:04
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementM-T: A feature request for new functionalitysemver:minorVersion: 3xweb-client

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@zimeg@mwbrooks@WilliamBergamin@srtaalej