Skip to content

fix(slack): pass token through native stream stop#573

Merged
dancer merged 2 commits into
mainfrom
josh/slack-stream-token
Jun 1, 2026
Merged

fix(slack): pass token through native stream stop#573
dancer merged 2 commits into
mainfrom
josh/slack-stream-token

Conversation

@dancer

@dancer dancer commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator

summary

fixes #570

fixes Slack native streaming when the stream reaches stop() before a token-bearing append has flushed

SlackAdapter.stream() now passes the resolved bot token on every streamer.append() and on streamer.stop(), matching Slack's auth requirements and avoiding not_authed responses from chat.startStream / chat.stopStream

adds regression coverage for buffered markdown streams and repeated structured chunk appends

@dancer dancer requested a review from a team as a code owner June 1, 2026 19:54
@vercel

vercel Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
chat Ready Ready Preview, Comment, Open in v0 Jun 1, 2026 8:25pm
chat-sdk-nextjs-chat Ready Ready Preview, Comment, Open in v0 Jun 1, 2026 8:25pm

Comment thread packages/adapter-slack/src/index.test.ts Outdated
@dancer dancer merged commit 999d268 into main Jun 1, 2026
17 checks passed
@dancer dancer deleted the josh/slack-stream-token branch June 1, 2026 21:05
patrick-chinchill pushed a commit to Chinchill-AI/chat-sdk-python that referenced this pull request Jun 18, 2026
Port of upstream 999d268: SlackAdapter.stream() now passes the resolved
bot token on every streamer.append() (markdown deltas and structured
chunks) and on streamer.stop(), instead of only on the first append.
Fixes not_authed from chat.startStream/chat.stopStream when a stream
reaches stop() before a token-bearing append has flushed (e.g. fully
buffered markdown).

Composes with the existing multi-workspace plumbing: token is resolved
once at stream entry via _get_token() (request-context installation
token -> per-request resolved default -> static cache), then threaded
through all streamer calls; a Python-only regression test locks the
request-context token flowing through append and stop.

https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64
patrick-chinchill added a commit to Chinchill-AI/chat-sdk-python that referenced this pull request Jun 18, 2026
,523,553,573) (#141)

* feat(whatsapp): typing indicator support (vercel/chat#320)

Port of upstream ffc43fc:
- start_typing resolves the latest inbound message ID from the
  ThreadHistoryCache and posts a typing_indicator payload (which also
  marks the referenced message as read); no-ops with a warning when no
  inbound message context exists
- Graph API default version bumped v21.0 -> v25.0
- _graph_api_request and the typing-indicator failure path raise
  AdapterError instead of RuntimeError/plain Error
- new WhatsAppTypingIndicatorResponse TypedDict

https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64

* fix(gchat): collapse redundant autolink formatting for email links (vercel/chat#553)

Port of upstream 177735a: when a link node's visible label equals its
URL minus a mailto:/tel: scheme (e.g. an autolinked email address),
from_ast emits the bare value as plain text instead of the verbose
<url|text> form. Labels differing from the address keep <url|text>.

The collapse sits between the linkText==url shortcut and this port's
documented divergent branches (empty-label bare-URL emit and the
text-(url) fallback for unsafe labels/URLs), matching upstream's
check order; when it fires the output is plain text, so it never
produces the malformed forms those divergences guard against. Our
subset parser does not autolink bare emails/URLs (Known Limitations),
so the ported collapse tests build the autolink-shaped node via the
explicit markdown form, plus a Python-only round-trip test through the
divergent <url|text> to_ast path.

https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64

* fix(slack): resolve reaction user display names (vercel/chat#523)

Port of upstream b63c042: reaction events now resolve
event.user.user_name / full_name / is_bot from the cached
_lookup_user() (users.info) path instead of echoing the raw Slack user
ID, falling back to the user ID (and is_bot=False) when lookup fails.

Also completes the dispatch-key test's mock client/state contract
(users_info + async state methods), mirroring the upstream test update
- a bare AsyncMock's auto-children made users.info results async and
leaked an orphaned coroutine through the new lookup.

https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64

* fix(slack): pass token through native stream stop (vercel/chat#573)

Port of upstream 999d268: SlackAdapter.stream() now passes the resolved
bot token on every streamer.append() (markdown deltas and structured
chunks) and on streamer.stop(), instead of only on the first append.
Fixes not_authed from chat.startStream/chat.stopStream when a stream
reaches stop() before a token-bearing append has flushed (e.g. fully
buffered markdown).

Composes with the existing multi-workspace plumbing: token is resolved
once at stream entry via _get_token() (request-context installation
token -> per-request resolved default -> static cache), then threaded
through all streamer calls; a Python-only regression test locks the
request-context token flowing through append and stop.

https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64

* fix(slack): emit uploadedFileIds (camelCase) on raw to match upstream chat@4.30.0

Our Python-only "file-ids" surface (Slack-confirmed upload IDs exposed on
RawMessage.raw so consumers can gate on actual delivery) was adopted
upstream in chat@4.30.0, which emits the synthetic key as camelCase
`uploadedFileIds`. We were emitting snake_case `uploaded_file_ids`,
leaving a divergence at the serialization boundary.

Rename the emitted dict key to `uploadedFileIds` so consumers reading the
raw payload match the upstream/TS surface. The local variable stays
snake_case (`uploaded_file_ids`) per the "snake_case internal, camelCase
at boundary" rule; only the key merged into `raw` changes. Behavior is
otherwise identical (None -> raw unchanged; empty list preserved as the
zero-attachments signal).

Updates the three Python-only tests that asserted the old key name
(test_slack_api file-upload tests and the test_thread_faithful raw-
propagation test, which uses Slack's surface as its example payload).

https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Slack adapter: streamer.stop() called without token causes not_authed when first append never sets it

2 participants