You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: adapter hygiene — slack stream await, teams divider, public worker APIs
Bundles four open adapter issues into one PR.
- #44 SlackAdapter.stream(): await chat_stream(...). Without the await
the code called .append on an unawaited coroutine and native Slack
streaming failed on the first chunk. Existing tests were updated to
use AsyncMock for chat_stream so they mirror the real AsyncWebClient.
- #45 Teams divider now renders a visible separator. Dividers between
siblings hoist separator: True onto the next element; a trailing
divider emits a minimal non-empty Container. An empty Container with
separator: True renders at zero height in Microsoft Teams.
Documented as a divergence from upstream (same bug in TS).
- #46 New Chat.thread(thread_id, *, current_message=None) public
factory. Mirrors TS chat.thread(threadId). Lets worker processes
rebuild a Thread without reaching into ThreadImpl/_ThreadImplConfig
internals. current_message is preserved for Slack native streaming
(it populates recipient_user_id / recipient_team_id).
- #47 New SlackAdapter.current_token / current_client properties.
Public accessors for the request-context-bound token and a
preconfigured AsyncWebClient. Replaces underscore-prefixed
_get_token / _get_client access from consumer code that makes direct
Slack Web API calls from inside a handler.
Tests and CHANGELOG updated. UPSTREAM_SYNC.md divergence table updated
for #45 and #47.
https://claude.ai/code/session_01MXobPieFH93txkgm38oMpC
Copy file name to clipboardExpand all lines: CHANGELOG.md
+10Lines changed: 10 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,15 @@
1
1
# Changelog
2
2
3
+
## Unreleased
4
+
5
+
### Fixes
6
+
-**Slack native streaming no longer crashes on first chunk** (issue #44): `SlackAdapter.stream()` now awaits `AsyncWebClient.chat_stream(...)`; the previous code called `.append()` on an unawaited coroutine, raising `AttributeError` and forcing callers onto the post+edit fallback. Existing tests were updated to use `AsyncMock` for `chat_stream` so they mirror the real client.
7
+
-**Teams divider now renders a visible separator line** (issue #45): `card_to_adaptive_card` previously emitted an empty `Container` with `separator: True`, which Microsoft Teams renders at zero height. The new behavior hoists `separator: True` onto the following sibling (or emits a minimal non-empty Container for a trailing divider). Upstream TS ships the same bug; documented as a divergence in [UPSTREAM_SYNC.md](docs/UPSTREAM_SYNC.md).
8
+
9
+
### Python-only additions
10
+
-**`SlackAdapter.current_token` / `current_client`** (issue #47): public `@property` accessors that return the request-context-bound bot token and a preconfigured `AsyncWebClient`. Replaces reaching into `_get_token()` / `_get_client()` from consumer code that needs to call the Slack Web API directly from inside a handler (email resolution, user profile fetches, etc.). TS keeps `getToken()` private; documented as a Python-only extension in [UPSTREAM_SYNC.md](docs/UPSTREAM_SYNC.md).
11
+
-**`Chat.thread(thread_id, *, current_message=None)`** (issue #46): public worker-reconstruction factory mirroring TS `chat.thread(threadId)`. Adapter is inferred from the thread ID prefix; state and message history come from the Chat instance. Pass `current_message` when the worker needs Slack native streaming (it populates `recipient_user_id` / `recipient_team_id`).
12
+
3
13
## 0.4.26 (2026-04-16)
4
14
5
15
Synced to [Vercel Chat 4.26.0](https://github.com/vercel/chat).
Copy file name to clipboardExpand all lines: docs/UPSTREAM_SYNC.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -455,6 +455,8 @@ stay explicit instead of being rediscovered in code review.
455
455
| Google Chat image rendering | Images emit as `{alt} ({url})` or bare `url`| No image branch — falls through to default which concatenates children only, dropping the URL | Upstream silently drops image URLs when rendering to Google Chat text. We preserve the URL so the message content isn't lost. |
456
456
| Fallback streaming stream-exception capture |`_fallback_stream` captures exceptions from the stream iterator, flushes whatever content was already rendered, awaits `pending_edit`, and re-raises after cleanup |`try/finally` only — exception propagates immediately, `pendingEdit` is un-awaited, and the placeholder is stranded as `"..."`| Upstream leaves a hard UX failure when streams crash mid-flight (common: LLM connection drops): placeholder visible forever, orphan background task. We flush + clean up before re-raising so the caller still sees the original error and users see the partial content instead of a spinner. |
457
457
| Fallback streaming final SentMessage content | SentMessage + final edit carry `final_content` (remend'd — inline markers auto-closed) | SentMessage + final edit carry raw `accumulated`| Narrow UX refinement. If a stream ends with an unclosed `*`/`~~`/etc., upstream ships the unclosed marker; we run `_remend` so the user sees a clean final message. Not observable in the common case where streams close their own markers. |
458
+
| Teams divider rendering |`card_to_adaptive_card` hoists `separator: True` onto the next sibling (or emits a non-empty Container for a trailing divider) |`convertDividerToElement` emits an empty `Container` with `separator: True`| Upstream shares the same bug: Microsoft Teams renders an empty Container at zero height, so the separator line is effectively invisible. Python port fixes locally (issue #45) rather than blocking on upstream. |
459
+
|`SlackAdapter.current_token` / `current_client`| Public `@property` accessors that return the request-context-bound token and a preconfigured `AsyncWebClient`| Not exposed (`getToken()` is private on the TS `SlackAdapter`) | Python-only addition (issue #47). Downstream code that calls Slack Web APIs from inside a handler — email resolution, user profile fetches, reaction bookkeeping — otherwise depends on underscore-prefixed helpers. |
0 commit comments