Skip to content

v0.4.41 — sync to upstream chat@4.41.1

Latest

Choose a tag to compare

@patrick-chinchill patrick-chinchill released this 01 Oct 21:58
Immutable release. Only release title and notes can be modified.
6edbac5

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 default drop strategy, a second message arriving 30 s or more into a long handler (e.g. a long Slack/Teams stream) now raises LockError instead of running concurrently; pick queue/debounce/burst or set on_lock_conflict to handle it. Dedupe TTL is 10 minutes. wait_until no longer surfaces handler errors unless WebhookOptions(propagate_handler_errors=True). A failed adapter initialize() is cached until shutdown().
  • Mentions and the message model (#192, #193, #209, #283). Message.is_mention is tri-state: custom adapters must report None (not False) for "not detected". Emails, URL userinfo and @name-suffix no longer mention the bot. ast_to_plain_text keeps structural whitespace. On Slack, message.text is now the plain text of message.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 the U… user id. New Author.email / Author.is_system and Message.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() returns None without 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 explicit fallback_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_text defaults to UNSET; handle/DM threads have no stub current_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=False for workspace-wide access); getUser needs approval by default; link metadata is fenced as untrusted. to_ai_messages keeps 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 honor HTTPS_PROXY/HTTP_PROXY (set file_transport). Messenger, WhatsApp and Twilio narrow their media host/origin allowlists.
  • Webhook authentication (security). Telegram requires a webhook secret by default (#224; allow_unverified_webhooks escape hatch). Google Chat JWT verification is bound to configured identities; Pub/Sub and Workspace Add-on deployments must set the new service-account emails, and bot_user_id should be set (#222, #223). Slack caches are installation-scoped and Enterprise Grid org-wide installs work (#205, #268). Teams gains a custom token factory and webhook_verifier (#221).
  • Thread and channel ids. Linear agent sessions use one stable thread linear:{issue}:s:{session} (#232; re-subscribe old ids). Twilio channel_id equals the thread id (#235). Teams group chats carry a conversation-type segment and are no longer DMs; TeamsAdapter.bot_user_id is 28:{app_id} (#216, #217). Slack channel.post() returns a replyable slack:C…:<ts> (#283). Discord validates a thread's parent channel, and a thread interaction without parent_id encodes as discord:{guild}:{thread} (was discord:{guild}:{thread}:{thread}) (#229). WhatsApp Author.user_id and the thread's user segment may be a BSUID (e.g. US.1349…) for users without a shared phone number, and WhatsApp writes whatsapp:identity:alias:* / whatsapp:identity:route:* state keys (#236).
  • State and dispatch latency. Postgres set_if_not_exists now 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); Slack agent_view and Agent Sessions (#214, #215); cards Chart, 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 require slack-sdk>=3.40.0 (was >=3.27.0; needed for native stream rotation, #208). The [teams] extra allows microsoft-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 @Patrick became <@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/stopStream call returned 200, with no message_not_in_streaming_state and no lost or duplicated text. Rotation is by age only, so a long reply that streams fast can still hit Slack msg_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 main and oss/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-apps 2.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.