v0.4.26.1 — Python-only follow-up on 4.26
·
88 commits
to main
since this release
Immutable
release. Only release title and notes can be modified.
0.4.26.1 (2026-04-23)
Python-only follow-up on 0.4.26. Still alpha — APIs may change.
Fixes
- Slack native streaming:
SlackAdapter.stream()no longer calls
AsyncWebClient.chat_stream(...)withoutawait. The unawaited coroutine
returned a truthy object, and the firststreamer.append(...)raised
AttributeError, breaking native Slack streaming for any consumer using
the default adapter. Issue #44. - Teams divider renders at non-zero height: empty
Containerwith
separator: Truerendered as zero-height in the Teams UI. Dividers
between siblings now hoistseparator: Trueonto the following element;
a trailing divider emits a minimal non-empty Container. Issue #45. ConcurrencyConfig.max_concurrentis now enforced: consumers setting
concurrency=ConcurrencyConfig(strategy="concurrent", max_concurrent=N)
now actually get anasyncio.Semaphore(N)cap on in-flight handlers.
Previously the field was accepted and ignored (upstream TS has the same
gap).None/ unset keeps the unbounded default. Issue #51.
Python-specific (divergence from upstream 4.26)
- Fallback streaming runtime robustness (cluster of fixes): framework-
agnosticrequest.text()handling now tolerates sync Flask-style
requests (was raisingTypeError: object is not awaitable). Handlers
typedCallable[..., Awaitable[None] | None]may return sync (None) —
the dispatcher nowawaits only wheninspect.isawaitable()confirms,
preventing runtime crashes on sync handlers. max_concurrentenforcement (see above) — upstream accepts the
config field but never enforces it; we do.
New public APIs
Chat.thread(thread_id, *, current_message=None): new worker-
reconstruction factory mirroring TSchat.thread(threadId). Adapter is
inferred from the thread-ID prefix; state and message history come from
the Chat instance.current_messageis preserved so Slack native
streaming still works post-reconstruction. Issue #46.SlackAdapter.current_token/current_client: public@property
accessors for the request-context-bound bot token and a preconfigured
AsyncWebClient. Replaces underscore access from consumer code making
direct Slack Web API calls inside a handler (email resolution, user
profile fetches, etc.). Issue #47.
Internals
- Pyrefly: 213 → 0 type errors; baseline file removed. CI now enforces
zero errors. Root causes fixed: 8-adapterlock_scope: LockScope | None
protocol conformance;_ChatSingletonasProtocol; submodule-aware
replace-imports-with-any;NoReturnon error re-raisers;
inspect.isawaitableguards for duck-typed request handling and
sync-or-async handler dispatch. NoAnywidening, no new# type: ignorelines beyond 10 at adapter event-construction sites where
thread=None/channel=Noneget re-wrapped byChatbefore handler
dispatch (matches upstream TS'sOmit<>partial-event pattern). - Test count: 3545 passed, 2 skipped.
Known gaps (not fixed in this release)
onOptionsLoadhandler for dynamic select dropdowns — issue #50Thread.getParticipants()method — issue #54rehydrate_attachmentadapter hook for queue/debounce + attachments —
issue #52- 40 upstream tests without Python equivalents (Options Load, Plan variants,
StreamingPlan options, getParticipants) — issue #53 - Discord native Gateway WebSocket (HTTP-only today) — issue #57
- Teams certificate-based mTLS auth — issue #58
- Google Chat file uploads (TODO upstream too) — issue #59
- Global handler-dispatch bound across reactions/actions/slash/modals — issue #61