Releases: Chinchill-AI/chat-sdk-python
v0.4.26.3 — Slack render_postable AST fix
Python-only patch on top of vercel/chat@4.26.0. No upstream version change.
Fixes
SlackFormatConverter.render_postablenow uses the AST path for all markdown inputs (#81). Previously,PostableMarkdownand{"markdown": ...}dict inputs were routed through a private regex helper (_markdown_to_mrkdwn) that truncated URLs containing parentheses and diverged silently from the TS SDK'sfromAst(parseMarkdown(text))behavior. Both branches now callfrom_markdown, which goes through the AST.strandrawbranches are unchanged.
Structural parity
- Deleted
_markdown_to_mrkdwn— a regex-based private method with no call sites after the fix above. The TS SDK has no equivalent; its presence was an undocumented divergence.
Additions
render_postablenow handles card and object-with-ast inputs — added{"card": ...}dict,{"type": "card", ...}CardElementdict,{"ast": ...}dict, and.card/.astattribute branches, plusstr(message)fallback for unrecognized types. Matches the full union ofAdapterPostableMessagevariants.
Test quality
19 new tests in tests/test_slack_format.py (47 → 66) covering all render_postable branches, every _node_to_mrkdwn node type (heading, blockquote, thematic break, image with/without alt), the remaining extract_plain_text paths (strikethrough, bare URL, channel mentions), and to_blocks_with_table edge cases (non-dict AST, standalone table, column alignment).
v0.4.26.2 — upstream parity catch-up
Parity catch-up release with upstream vercel/chat@4.26.0.
Highlights
Thread.get_participants()(#54) — upstream-parity portonOptionsLoad+ Slackblock_suggestion(#50) — external-select dispatch with 2.5s timeoutrehydrateAttachmenthook + SSRF guards (#52) — 5-adapter implementations with per-adapter URL allowlistsStreamingPlan+StreamingPlanOptions(#56) — addskind=='stream'branch inThread.post()(options were previously silently dropped)IoRedisStateAdapter(#71) — cross-runtime Redis interop with TS deployments- Teams cert config shape (#58) — parity with upstream's deprecated-throws stub
- 20
[post with Plan]+ 6[Streaming]test ports (#55, #56) + 3 Plan divergence fixes (UpdateTaskInput.id, error propagation, FIFO edit queue) - Strict fidelity CI (#53) —
verify_test_fidelity.pywired into lint workflow, fails on any missing test or missing upstream checkout
Fidelity
588/588 matched (mapped core files) against chat@4.26.0. Closed [getParticipants], [thread], [Options Load], [post with Plan], [Streaming], and [concurrency: queue attachment rehydration] gaps.
Test coverage
3640 passed, 2 skipped (up from 3545 in 0.4.26.1).
Python-first divergences (documented in docs/UPSTREAM_SYNC.md)
StreamingPlan.is_supported()/get_fallback_text()raise on misroute (upstream silently posts blank)rehydrate_attachmentURL allowlists on Slack / Teams / Google Chat (SSRF defense — upstream doesn't validate)- Redis token format uses CSPRNG hex (upstream uses
Math.random()base36; interop preserved via full-string equality)
Follow-ups tracked
- #78 — extend fidelity MAPPING to all 17
packages/chat/src/*.test.tsfiles - #79 — pin upstream clone SHA in CI
- #80 — tighten fuzzy matcher against hyphen-stripped accidental matches
Full changelog: CHANGELOG.md
v0.4.26.1 — Python-only follow-up on 4.26
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
v0.4.25 — Synced to Vercel Chat 4.25.0
Synced to Vercel Chat 4.25.0. New versioning: 0.{upstream_major}.{upstream_minor} embeds the upstream version directly.
Upgrading
pip install chat-sdk==0.4.25Version scheme changed from 0.0.1aX to 0.{upstream_major}.{upstream_minor}[.patch]. Check chat_sdk.UPSTREAM_PARITY programmatically.
New features (from upstream 4.25.0)
- Plan blocks: Post structured task lists with live updates.
plan = Plan(title="Deploy steps") posted = await thread.post(plan) await plan.add_task("Build image") await plan.update_task(0, status="completed") await plan.complete()
- Streaming table option:
StreamingMarkdownRenderer(wrap_tables_for_append=False)for platforms with native table support. Slack uses this by default. - Teams Select/RadioSelect: Card elements render as Adaptive Card
Input.ChoiceSetwith auto-submit. - GitHub issue threads:
issue_commentwebhooks on plain issues create threads withgithub:owner/repo:issue:42. - Slack OAuth redirect fix:
handle_oauth_callbackcorrectly forwardsredirect_uri.
Python-only improvements (not in upstream)
- PostableObjects cached in message history with real message ID (upstream skips this)
- Teams
msteamstransport key stripped from action values (upstream leaks it) - End-to-end integration tests for Teams card inputs
- GitHub
fetch_threadround-trip test with channel APIs
Internals
- 3,421 tests, 0 warnings, 0 lint errors
- 535/535 TS fidelity (100%)
- Version mapping and sync procedure in UPSTREAM_SYNC.md
v0.0.1a12
Python 3.10 support, async-safe Chat resolver, and a large correctness audit.
Upgrading
Python 3.10 is now supported. CI tests 3.10 through 3.13.
Breaking changes (all alpha — no stable API guarantees yet):
- Serialization keys are now camelCase (
threadId,channelId,adapterName) to match the TS SDK.from_json()accepts both camelCase and snake_case, so existing stored data still loads. PermissionError→AdapterPermissionError: the old name shadowed Python's builtin.StateNotConnectedErrorreplaces bareRuntimeErrorwhen calling state methods beforeconnect().OnLockConflictcallbacks should return"force"or"drop"(strings). ReturningTruestill works but is deprecated.reviver()no longer registers a global singleton. Each reviver is bound to the Chat that created it.
New: async-safe Chat resolver
Thread and Channel deserialization now supports three resolution levels:
# 1. Explicit (best for library code, multi-tenant)
thread = ThreadImpl.from_json(data, chat=my_chat)
# 2. Context-local (best for tests, request scoping)
with chat.activate():
thread = ThreadImpl.from_json(data)
# 3. Global (existing pattern, unchanged)
chat.register_singleton()Bug fixes
- Fixed streaming: intermediate edits now use the markdown renderer, paragraph separators between agent steps, 500ms latency on stream end eliminated
- Fixed all adapters: token refresh race conditions, HTTP session reuse,
limit=0no longer silently replaced by defaults - Fixed serialization: Slack installations interoperate with TS SDK, card fallback text extracted properly, AI SDK field names corrected
- Fixed Teams: status code comparison, modal dialog buttons, table cell escaping
- Fixed shutdown: in-flight handler tasks cancelled, fire-and-forget tasks tracked for GC safety
- 30+ additional production bug fixes (see CHANGELOG)
Internals
- 3,360 tests, 0 warnings, 0 lint errors, 535/535 TS fidelity
- Automated test quality gate in CI
- Porting guide with 15 hazards and merge checklist
v0.0.1a11 — 100% Test Fidelity
529/529 TS tests matched (100%). 3,427 tests. verify_test_fidelity.py enforces 1:1 name correspondence going forward.
v0.0.1a8 — Full Test Parity
3,106 tests. All components at 94%+ of TypeScript test count. See CHANGELOG.md.
v0.0.1a7 — Coverage & Fixtures
82% coverage (up from 79%). 2,767 tests. All 46 fixture replay tests pass. Postgres atomic lock. Core SDK test gaps documented.
v0.0.1a6 — Systematic Port Fidelity
10 more port bugs fixed from systematic TS comparison. See CHANGELOG.md.
v0.0.1a5 — Port Fidelity Release
10 critical/high port bugs fixed from systematic comparison against TS originals. See CHANGELOG.md for details.