Repository navigation
Synced to upstream vercel/chat@4.41.1 (the 4.41 wave, tracking #184): twelve upstream releases (chat@4.32.0 → chat@4.41.1) in one jump from chat@4.31.0. Sets UPSTREAM_PARITY = "4.41.1" (the exact strict fidelity pin tag, not 4.41.0; the package version encodes only major.minor). The strict fidelity pin moves to chat@4.41.1 (f690af3c): 922/922 mapped tests at the pin, up from 733/733 at chat@4.31.0, after the eight test files upstream added in 4.34–4.41 (history/*, agent-session, app-context, installation-events, adapter-shared/download) joined the strict tier. cards, modals, emoji and message stay report-only (100 of 142 upstream titles untranslated; issue #78). Upstream changes the wave skips (TanStack AI, AI SDK v7 typing, Workflow requestApproval, the serialization entrypoint, Vercel Connect, create-chat-sdk, catalog/docs-only commits) and the demand-gated platforms (Instagram, Notion, X, XChat, Telegram Business, Twilio RCS, Gmail #241, Discord Components V2, per-adapter Vercel Connect; #189) are recorded in docs/UPSTREAM_SYNC.md § Known Non-Parity.
Consumer-visible changes (migration checklist)
Each item names the wave issues; their entries under "Wave PRs" below have the details and migration notes.
- Concurrency (#190, #191). Thread/channel locks now heartbeat while a handler runs (
max_lock_lifetime_ms, default 10 min). With the defaultdropstrategy, a second message arriving 30 s or more into a long handler (e.g. a long Slack/Teams stream) now raisesLockErrorinstead of running concurrently; pickqueue/debounce/burstor seton_lock_conflictto handle it. Dedupe TTL is 10 minutes.wait_untilno longer surfaces handler errors unlessWebhookOptions(propagate_handler_errors=True). A failed adapterinitialize()is cached untilshutdown(). - Mentions and the message model (#192, #193, #209, #283).
Message.is_mentionis tri-state: custom adapters must reportNone(notFalse) for "not detected". Emails, URL userinfo and@name-suffixno longer mention the bot.ast_to_plain_textkeeps structural whitespace. On Slack,message.textis now the plain text ofmessage.formatted(no mrkdwn markup), the bot's own mention reads@BotName, special mentions read@here/@eng, code blocks keep their first line, and bot authors use theU…user id. NewAuthor.email/Author.is_systemandMessage.reply_to. - Streaming (#199, #207, #208, #219, #226, #206). Slack:
native_streaming, a post+edit fallback (top-level DMs now stream by editing a placeholder),stream()returnsNonewithout recipient context instead of raising, long native streams continue in a new message before Slack's ~5 min expiry (stream_segment_max_age_ms), and streamed@names become real pings. Teams (#219): only with an explicitfallback_streaming_placeholder_text, DMs show it as the native informative status line and group chats/channels stream by post+edit; otherwise unchanged. Telegram: post-and-edit by default, native drafts opt-in. Core:fallback_streaming_placeholder_textdefaults toUNSET; handle/DM threads have no stubcurrent_message. - Callback-URL tokens (#194, security). Single-use, bound to their button and conversation, 7-day TTL. Tokens minted before the upgrade stop resolving.
- AI tools (#195, #198, security). Agent tools are confined to the conversation being handled (
scope=Falsefor workspace-wide access);getUserneeds approval by default; link metadata is fenced as untrusted.to_ai_messageskeeps attachment/link-only messages;ChatTool.name. - Download caps (#204 and adopters #213, #218, #225, #229, #234, #235, #239). Attachment downloads go through the shared guarded downloader: HTTPS only, internal addresses refused (including after redirects), 25 MB decoded cap, 30 s deadline, failures raise
NetworkError. Slack file downloads no longer honorHTTPS_PROXY/HTTP_PROXY(setfile_transport). Messenger, WhatsApp and Twilio narrow their media host/origin allowlists. - Webhook authentication (security). Telegram requires a webhook secret by default (#224;
allow_unverified_webhooksescape hatch). Google Chat JWT verification is bound to configured identities; Pub/Sub and Workspace Add-on deployments must set the new service-account emails, andbot_user_idshould be set (#222, #223). Slack caches are installation-scoped and Enterprise Grid org-wide installs work (#205, #268). Teams gains a custom token factory andwebhook_verifier(#221). - Thread and channel ids. Linear agent sessions use one stable thread
linear:{issue}:s:{session}(#232; re-subscribe old ids). Twiliochannel_idequals the thread id (#235). Teams group chats carry a conversation-type segment and are no longer DMs;TeamsAdapter.bot_user_idis28:{app_id}(#216, #217). Slackchannel.post()returns a replyableslack:C…:<ts>(#283). Discord validates a thread's parent channel, and a thread interaction withoutparent_idencodes asdiscord:{guild}:{thread}(wasdiscord:{guild}:{thread}:{thread}) (#229). WhatsAppAuthor.user_idand the thread's user segment may be a BSUID (e.g.US.1349…) for users without a shared phone number, and WhatsApp writeswhatsapp:identity:alias:*/whatsapp:identity:route:*state keys (#236). - State and dispatch latency. Postgres
set_if_not_existsnow reclaims an expired row, so Postgres-backed dedupe keys and leases recover without cleanup (#240). Teams looks up the sender's email before dispatch: on a cache miss that is one awaited network call, bounded at 5 s, cached for 1 h (#218). - New lifecycle and API surface (additive).
on_message_updated/on_message_deleted,on_installed/on_uninstalled, app-context and agent-session events (#196, #201, #211, #215, #217);chat.history(#197);Thread.reply/Thread.mark_as_read(#200); turn cancellation (chat.abort_turn,thread.signal, #201); Slackagent_viewand Agent Sessions (#214, #215); cardsChart, table options, tooltips,DateInput/NumberInput(#202, #212, #220); Telegram albums and media groups (#227, #278); WhatsApp templates, media and read receipts (#237, #238, #239). - Dependencies. The
[slack]/[slack-socket]extras requireslack-sdk>=3.40.0(was>=3.27.0; needed for native stream rotation, #208). The[teams]extra allowsmicrosoft-teams-{apps,api,cards,common}>=2.0.13,<2.2(#250).
Live validation (2026-10-01)
Run on chinchill's customer-demo Slack app: oss/agent-framework plus the 0.4.41 adoption at @0fd3cc3, with a test-only 20 s stream-segment cap. Every live Slack result below was re-checked independently against Slack and Logfire. The Teams and Agent Sessions items were not run live. Demo was restored afterwards.
- Slack streamed mentions (#206): a streamed
@Patrickbecame<@U0917L892RX>on the native stream path; code spans and URLs were left untouched. - Slack stream rotation (#208): one reply split into two consecutive messages. Every
startStream/appendStream/stopStreamcall returned 200, with nomessage_not_in_streaming_stateand no lost or duplicated text. Rotation is by age only, so a long reply that streams fast can still hit Slackmsg_too_long. Upstream has the same gap; it's tracked in #310, not a 0.4.41 regression. - Downstream git-ref smoke test (chinchill): on both
mainandoss/agent-framework, chinchill's chat_sdk boundary suites (743 and 1004 tests) and CI Tests/Lint passed. - Basic native streaming, outbound markdown/code rendering, DMs, and a Logfire error sweep: all clean. Inbound mrkdwn normalization was not covered by a dedicated live check; it is covered by the ported tests.
- Teams on SDK 2.1 (#262 / #250): not live-verified, because no Teams tenant is available. The full suite passes on
microsoft-teams-apps2.1.0, and the Teams and fixture-replay suites also pass on 2.0.16 and 2.0.13.4. - Slack Agent Sessions native Stop (#215): not live-verified. It is opt-in and only runs with a Slack app that has the Agent messaging experience enabled and
agent_view=True; chinchill enables neither. Covered by the ported upstream tests.
Known gap: long replies that stream fast can exceed Slack's per-message limit (msg_too_long); tracked in #310 (upstream has the same gap).
The full per-PR notes (about 55 wave PRs, security fixes and Python-specific divergences) are in CHANGELOG.md § 0.4.41. Tracking issue: #184.