chat
4.43.0 · 19 Oct 2026MIT2.1M / weekRepositoryHomepagenpmAtom feed
88 stable releases, newest first, by release line. Notes are quoted as the maintainers published them.
4.43.0
19 Oct 2026115cd39: Add
@chat-adapter/gitlabfor merge request and issue comment threads on GitLab.com, GitLab Self-Managed, and GitLab Dedicated. It verifies webhooks with a signing token or secret token, replies inside each comment's discussion, handles emoji reactions, uploads files, and resolvesmessage.subjectto the parent merge request or issue. Registers the adapter in@chat-adapter/catalogand thecreate-chat-sdkCLI scaffold, and adds GitLab emoji platform support.a32470e: Keep literal tildes, asterisks, underscores, and backslashes as written in outgoing WhatsApp messages. A backslash escape is kept only where the text would otherwise turn into WhatsApp formatting, such as
\_word\_or a line starting with\>. Render bold, italic, and strikethrough from their AST nodes so formatting markers inside inline and fenced code stay unchanged, and send hard breaks as plain newlines. Add ahandlersoption tostringifyMarkdownfor platform-specific serialization.228b30d: Pass the current message ID to
Adapter.startTypingasTypingOptions.messageId.
Minor Changes
115cd39: Add
@chat-adapter/gitlabfor merge request and issue comment threads on GitLab.com, GitLab Self-Managed, and GitLab Dedicated. It verifies webhooks with a signing token or secret token, replies inside each comment's discussion, handles emoji reactions, uploads files, and resolvesmessage.subjectto the parent merge request or issue. Registers the adapter in@chat-adapter/catalogand thecreate-chat-sdkCLI scaffold, and adds GitLab emoji platform support.a32470e: Keep literal tildes, asterisks, underscores, and backslashes as written in outgoing WhatsApp messages. A backslash escape is kept only where the text would otherwise turn into WhatsApp formatting, such as
\_word\_or a line starting with\>. Render bold, italic, and strikethrough from their AST nodes so formatting markers inside inline and fenced code stay unchanged, and send hard breaks as plain newlines. Add ahandlersoption tostringifyMarkdownfor platform-specific serialization.228b30d: Pass the current message ID to
Adapter.startTypingasTypingOptions.messageId.
4.42.0
14 Oct 2026daaa0ac: Add
@chat-adapter/catalog, a zero-dependency catalog of every adapter on chat-sdk.dev. It lists official, vendor-official, and community adapters with their npm package, maintainer, README, and capability support, plus the factory export, peer dependencies, and environment variables for official and vendor-official adapters. New helpers includelistAdapters(),getCatalogEntry(), andgetFeatureSupport().The
chat/adapterssubpath is now deprecated. It re-exports the original API from@chat-adapter/catalog, so existing imports keep working. ItsADAPTERSkeeps alphabetical key order, and itsCatalogAdaptertype accepts objects without the newfeaturesandreadmefields. In@chat-adapter/catalog,ADAPTERSfollows chat-sdk.dev listing order andCatalogAdapterrequires both fields.create-chat-sdkreads adapter metadata from@chat-adapter/catalog.getAdapter()andlistEnvVars()now returnundefinedand `` for inherited object keys such as"toString", instead of returningObject.prototypemembers.fd291b8: feat(teams): let a card carry a text input
TextInput, which modals already use, is now also aCardChild, so a user can type a reply on the card instead of opening a dialog. Teams renders it as an Adaptive CardInput.Textwith the same mapping the modal converter uses, and the@chat-adapter/teams/cardssubpath emits the same element. Slack, Google Chat, Discord, GitHub, and Linear show its label as text. WhatsApp, Messenger, Twilio, and X omit it, so don't make an input the only content on a card that reaches them.ActionEventgainsvalues?: Record<string, string>, the card's own input values keyed by input ID. It has the same shape asModalSubmitEvent.values. The Teams adapter fills it from theAction.Submitpayload, and it is absent on platforms with no card inputs. A button'scallbackUrlPOST now carriesvaluestoo, so a webhook-driven flow with noonActionhandler still receives what was typed.An input is required unless
optionalis set, and Teams validates every input on the card before it lets a button through, so mark itoptionalunless the buttons beside it should be blocked until it is filled. That validation is client-side, so treatvaluesas user input and validate it in the handler. A Teams button withactionType: "modal"now renders withassociatedInputs: "none", so it opens its dialog without waiting on the card's inputs and doesn't send them.Teams merges card inputs into the button's own submit data, so a card
TextInputwith the IDactionId,value, ormsteamsthrows aValidationErrorwhen the card is rendered, and the@chat-adapter/teams/cardssubpath throws anError. Modal inputs can still useactionIdandvalue.CardChildgained a member, so an adapter outside this repo that exhausts the union with anevercheck needs atext_inputcase. Every in-repo converter reaches it through adefault:branch instead, so none needed changing.19c7aa2: Add a handler-only
onNewMessage(handler)overload for messages that reach pattern routing, including attachment-only messages without text. InvalidonNewMessagearguments now throw aChatErrorat registration.
Minor Changes
daaa0ac: Add
@chat-adapter/catalog, a zero-dependency catalog of every adapter on chat-sdk.dev. It lists official, vendor-official, and community adapters with their npm package, maintainer, README, and capability support, plus the factory export, peer dependencies, and environment variables for official and vendor-official adapters. New helpers includelistAdapters(),getCatalogEntry(), andgetFeatureSupport().The
chat/adapterssubpath is now deprecated. It re-exports the original API from@chat-adapter/catalog, so existing imports keep working. ItsADAPTERSkeeps alphabetical key order, and itsCatalogAdaptertype accepts objects without the newfeaturesandreadmefields. In@chat-adapter/catalog,ADAPTERSfollows chat-sdk.dev listing order andCatalogAdapterrequires both fields.create-chat-sdkreads adapter metadata from@chat-adapter/catalog.getAdapter()andlistEnvVars()now returnundefinedand `` for inherited object keys such as"toString", instead of returningObject.prototypemembers.fd291b8: feat(teams): let a card carry a text input
TextInput, which modals already use, is now also aCardChild, so a user can type a reply on the card instead of opening a dialog. Teams renders it as an Adaptive CardInput.Textwith the same mapping the modal converter uses, and the@chat-adapter/teams/cardssubpath emits the same element. Slack, Google Chat, Discord, GitHub, and Linear show its label as text. WhatsApp, Messenger, Twilio, and X omit it, so don't make an input the only content on a card that reaches them.ActionEventgainsvalues?: Record<string, string>, the card's own input values keyed by input ID. It has the same shape asModalSubmitEvent.values. The Teams adapter fills it from theAction.Submitpayload, and it is absent on platforms with no card inputs. A button'scallbackUrlPOST now carriesvaluestoo, so a webhook-driven flow with noonActionhandler still receives what was typed.An input is required unless
optionalis set, and Teams validates every input on the card before it lets a button through, so mark itoptionalunless the buttons beside it should be blocked until it is filled. That validation is client-side, so treatvaluesas user input and validate it in the handler. A Teams button withactionType: "modal"now renders withassociatedInputs: "none", so it opens its dialog without waiting on the card's inputs and doesn't send them.Teams merges card inputs into the button's own submit data, so a card
TextInputwith the IDactionId,value, ormsteamsthrows aValidationErrorwhen the card is rendered, and the@chat-adapter/teams/cardssubpath throws anError. Modal inputs can still useactionIdandvalue.CardChildgained a member, so an adapter outside this repo that exhausts the union with anevercheck needs atext_inputcase. Every in-repo converter reaches it through adefault:branch instead, so none needed changing.19c7aa2: Add a handler-only
onNewMessage(handler)overload for messages that reach pattern routing, including attachment-only messages without text. InvalidonNewMessagearguments now throw aChatErrorat registration.08081fa: Reject AI tool calls that have no conversation scope when they run inside a handler with no conversation, such as an action in App Home or inside a modal, an options-load handler, or a modal opened outside a thread or channel. Pass an explicit
scope, orscope: falsefor intentionally workspace-wide access. Calls outside any handler, such as in a cron job or script, still run workspace-wide and log a warning. An emptyscopeid now throws when the tools are created.The standalone tool factories exported from
chat/ai, such asfetchMessagesandpostMessage, now acceptscopeandstrictScopeand follow the same rules ascreateChatTools. Inside a handler they inherit the conversation being handled, so a call that targets another channel is now rejected. Outside a handler they log the same unscoped warning once per tool. Passing a guard function still works but is deprecated in favor ofscope.7b7d73c: Add a
visibleTooption toButtonandLinkButtonthat lists the user IDs allowed to see the button. The Slack adapter renders it asvisible_to_user_ids. Other adapters ignore it and show the button to everyone. It only hides the button, so action handlers still need to check who clicked.f8527b2: Add an optional
aiGeneratedfield toPostableRaw,PostableMarkdown,PostableAst,PostableCard,StreamingPlanOptions, andStreamOptions. When it'strue, adapters with a native AI label show it. The Teams adapter shows Teams' "AI generated" label on new, edited, channel, targeted, and streamed messages. An edit must set the flag again to keep the label. The built-in AI tools now setaiGenerated: trueon themarkdownandrawmessages they post or edit.9a83b22: Isolate Slack message concurrency and turn cancellation by installation to prevent cross-workspace bot token reuse. Adapters can now namespace dedupe, lock, queue, and turn keys with the optional
Adapter.getConcurrencyScope()hook. In multi-workspace mode, messages queued under the old keys aren't migrated, and old and new workers don't exclude each other, so upgradechatand@chat-adapter/slacktogether and restart all workers.f635dbe: Add a Twitch adapter. It reads channel chat through EventSub webhooks, replies with the Helix Chat API as a bot account, deletes messages as a moderator, and sends and receives whispers. The
chat/adapterscatalog andcreate-chat-sdknow include Twitch.
Patch Changes
2f1cfa2: Allow
SlackAdapterandTelegramAdapterto be assigned toAdapterwhenexactOptionalPropertyTypesis enabled.19c7aa2: Fix
onNewMessagepatterns with the global or sticky flag so they match on every message instead of skipping alternate ones.80e7bae: Stop describing the ioredis state adapter as supporting Redis Cluster. Its
clientoption accepts an ioredisRedisinstance, which aClusterdoesn't satisfy; Sentinel is still supported.08081fa: Keep modal context until the modal closes, so
relatedThreadandrelatedChannelare still available when a user resubmits after a submit handler returns validation errors, or after anupdateorpushresponse.8178fdb: Fix Workflow DevKit workflows failing to start with
ReferenceError: AbortController is not defined. The default thread signal is now created on first use, and threads revived inside the workflow VM get an inert signal that never aborts.
4.41.0
18 Sep 2026ad90432: Add opt-in selection change events for Select and RadioSelect inputs in Slack modals
dc2a777: Add TanStack AI support.
thread.post(),thread.reply(), andchannel.post()accept the stream returned by TanStack'schat(), and the newchat/ai/tanstacksubpath providestoTanStackMessagesfor thread history andcreateTanStackToolsfor the Chat SDK toolset. Neither adds a runtime dependency on@tanstack/ai; the tools require zod 4.2 or newer.139d337: Support Vercel Connect in the Teams adapter with lazy app identity resolution and custom webhook verification. Ensure custom Bot Framework and Graph token factories take precedence over client-secret environment variables.
Add Teams to
create-chat-sdk --connectand interactive Connect scaffolding, including the helper, connector environment variable, and setup documentation.
Minor Changes
ad90432: Add opt-in selection change events for Select and RadioSelect inputs in Slack modals
dc2a777: Add TanStack AI support.
thread.post(),thread.reply(), andchannel.post()accept the stream returned by TanStack'schat(), and the newchat/ai/tanstacksubpath providestoTanStackMessagesfor thread history andcreateTanStackToolsfor the Chat SDK toolset. Neither adds a runtime dependency on@tanstack/ai; the tools require zod 4.2 or newer.139d337: Support Vercel Connect in the Teams adapter with lazy app identity resolution and custom webhook verification. Ensure custom Bot Framework and Graph token factories take precedence over client-secret environment variables.
Add Teams to
create-chat-sdk --connectand interactive Connect scaffolding, including the helper, connector environment variable, and setup documentation.2e2426d: Add
onInstalledandonUninstalledhandlers for installation lifecycle events. The Teams adapter emits them forinstallationUpdateactivities, including theadd-upgradeandremove-upgradeactions, with a persistablechannelIdfor later proactive messages.The Teams adapter now sends, edits, deletes, reacts, and types against the service URL encoded in the thread ID instead of the app-wide default, so conversations hosted on regional or sovereign Bot Framework endpoints are reached correctly. An explicit
apiUrlstill pins every call to that endpoint.8421953: feat(teams): render tables as the Adaptive Card 1.5 Table element
The Teams adapter now renders
Tableas the native Adaptive CardsTableelement instead of aContainerofColumnSets. Teams draws grid lines between cells, sizes columns by relative weight and marks the header row for accessibility. The@chat-adapter/teams/cardssubpath emits the same element.Tablegains optional rendering options that only Teams reads:widths(positive integer column weights),verticalAlign(vertical alignment of cell content),gridLines(defaulttrue) andgridStyle. Other adapters ignore them. PassgridLines: falseto keep a borderless table.The chat JSX runtime now forwards
alignon<Table>, matchingfromReactElement.056d883: Allow
history.user.maxPerUserand legacytranscripts.maxPerUserto befalseto disable count-based history eviction. The default remains 200 entries per user.fcdc1c9: Honor an adapter's definitive
isMention: falseinstead of re-detecting mentions from the message text.An adapter that reads structured platform content reports
trueorfalse, and the SDK falls back to matching@usernamein the text only when the adapter reports nothing. A definitivefalsenow wins, so an adapter can suppress a mention that exists only in text its platform renders literally, such as a code sample. Adapters that previously returnedfalseto mean "not detected" should returnundefinedinstead. Direct messages are unchanged: with noonDirectMessagehandler registered they still route toonNewMention.Adapter changes that follow from the new contract:
Linear: ordinary comments are left undetermined, so SDK text detection still applies to them.
Notion:
keywordmode leaves comments without a keyword match undetermined instead of reportingfalse, so@userNamein the text still counts.X: posts rebuilt from raw or fetched by id are left undetermined instead of reporting
false. Onlypost.mention.createevents reporttrue.Discord: a real ping, role mention,
@everyone, or allowlisted channel reportstrue; anything else is left undetermined instead offalse, so a literal@botnametyped in the text still counts as before.
Patch Changes
f233ffe: Retry initialization after a failed state connection. Once the state adapter (for example Redis) recovers, the next
initialize()call or webhook tries again instead of rejecting with the original connection error. Concurrent callers still share one attempt. Adapter initialization failures remain cached untilshutdown()so retries cannot restart adapters that are already running or still starting.91683e5: Wait for Telegram polling handlers to settle before advancing update offsets.
c21ccbc: Add an opt-in webhook option to propagate message, action, and slash command handler errors through
waitUntilwhile preserving default behavior.
4.40.0
5 Sep 20264a0b5c0: Add
tooltiptoButtonandLinkButton, and awidthhint toCard. The Teams adapter and the@chat-adapter/teams/cardssubpath render them as the Adaptive Card actiontooltipand themsteamsfull-width card property; other adapters ignore them. Emitted Adaptive Cards now declare schema version 1.5, which is the version that introduced action tooltips. Buttons with acallbackUrlkeep theirtooltipand other fields when the URL is swapped for a callback token.f485255: Harden webhook tenant isolation, require explicit Google Chat bot identity for reliable mention handling, use native Google Chat pagination, isolate Slack caches, and bound recording storage.
b7c9316: Tighten AI tool and queued-message scoping, isolate direct-message conversations, preserve ephemeral follow-ups, consume callback tokens once, and mark external link metadata as untrusted.
4.39.0
28 Aug 20262ce2be0: Add Slack Agent Sessions lifecycle support, native stop cancellation through
thread.signal, automatic session titles, and session stop/title-change events while preserving the legacyassistant_viewcompatibility path.169788b: Introduce the unified History API (
bot.history) with user, thread, and channel scopes.bot.history.userreplacesbot.transcriptsfor cross-platform per-user message persistence. The API surface is identical — migrate by changing thetranscriptsconfig key tohistory.userand updating call sites frombot.transcripts.*tobot.history.user.*.bot.transcriptsremains available as a deprecated alias.bot.history.threadandbot.history.channelexpose promise-based helpers for per-thread and per-channel message access, aligned with the existingthread.messagesandchannel.threads()iterators. Reads delegate to the adapter; adapters that persist history in the SDK-side store (persistThreadHistory: true) are served from that cache. An unregistered adapter prefix or an unsupported capability throws instead of returning an empty result.The new
toPromptEntrieshelper convertshistory.user.list()entries into{ role, content }messages ready for LLM prompts.The
TranscriptEntrytype is deprecated in favour ofHistoryEntry. Both are exported fromchat.5b538f6: Keep thread locks alive while message handlers run so queue, burst, and debounce strategies remain serialized beyond the lock TTL. Renewal is capped by the new
concurrency.maxLockLifetimeMsoption (default 10 minutes) so a hung handler cannot block a thread forever. When the heartbeat detects that lock ownership was lost, the queue drain and debounce loops stop instead of competing with the new lock holder, and the debounce loop now keeps draining messages that arrive while a handler is running instead of stranding them until the next webhook.
Minor Changes
2ce2be0: Add Slack Agent Sessions lifecycle support, native stop cancellation through
thread.signal, automatic session titles, and session stop/title-change events while preserving the legacyassistant_viewcompatibility path.169788b: Introduce the unified History API (
bot.history) with user, thread, and channel scopes.bot.history.userreplacesbot.transcriptsfor cross-platform per-user message persistence. The API surface is identical — migrate by changing thetranscriptsconfig key tohistory.userand updating call sites frombot.transcripts.*tobot.history.user.*.bot.transcriptsremains available as a deprecated alias.bot.history.threadandbot.history.channelexpose promise-based helpers for per-thread and per-channel message access, aligned with the existingthread.messagesandchannel.threads()iterators. Reads delegate to the adapter; adapters that persist history in the SDK-side store (persistThreadHistory: true) are served from that cache. An unregistered adapter prefix or an unsupported capability throws instead of returning an empty result.The new
toPromptEntrieshelper convertshistory.user.list()entries into{ role, content }messages ready for LLM prompts.The
TranscriptEntrytype is deprecated in favour ofHistoryEntry. Both are exported fromchat.5b538f6: Keep thread locks alive while message handlers run so queue, burst, and debounce strategies remain serialized beyond the lock TTL. Renewal is capped by the new
concurrency.maxLockLifetimeMsoption (default 10 minutes) so a hung handler cannot block a thread forever. When the heartbeat detects that lock ownership was lost, the queue drain and debounce loops stop instead of competing with the new lock holder, and the debounce loop now keeps draining messages that arrive while a handler is running instead of stranding them until the next webhook.
Patch Changes
16ea171: preserve adapter-returned thread ids when editing channel messages
eddcd7e: Return Telegram file downloads as portable ArrayBuffer data while preserving Buffer support in the shared attachment contract.
929878b: Allow JSX link buttons to include an explicit action ID.
500b7e6: enforce the conversation scope on write tools and stop trusting client-supplied message history in the web adapter
createChatToolsnow runs the same scope guard on write tools that read tools already used, so a thread or channel id the model supplies that resolves outside the scoped conversation is rejected before the write executes.sendDirectMessagetargets a user id rather than a conversation and stays gated by approval alone.The web adapter no longer treats the request body's
messagesarray as a source of conversation state. Only the latest user message is consumed, and tool parts are stripped from it so a browser cannot inject forged tool-call or approval state. Text, file, and custom data parts pass through unchanged; a message left with no parts after stripping is rejected with HTTP 400. Prior turns come from the state adapter whenpersistMessageHistoryis enabled.
4.38.0
14 Aug 20260f24cc3: Preserve normalized replied-to message context and populate it from Telegram replies.
bdeb2bf: Add a workflow-safe
chat/serializationentrypoint and isolate automatic Chat class serializers from Node-only runtime dependencies.a0cba02: Add Vercel Connect credential resolvers and custom webhook verification to the Discord adapter, with
create-chat-sdk --connectscaffolding for Discord bots.
Minor Changes
0f24cc3: Preserve normalized replied-to message context and populate it from Telegram replies.
bdeb2bf: Add a workflow-safe
chat/serializationentrypoint and isolate automatic Chat class serializers from Node-only runtime dependencies.a0cba02: Add Vercel Connect credential resolvers and custom webhook verification to the Discord adapter, with
create-chat-sdk --connectscaffolding for Discord bots.83ede7e: add native message replies with WhatsApp contextual reply support
18d4a23: Add a shared thread API for marking messages as read across WhatsApp, Messenger, and XChat.
Note for anyone calling
XchatAdapter.markAsRead()directly: it now rejects when a receipt fails instead of logging a warning and resolving. Automatic read receipts are unaffected, since the adapter still catches and logs those internally. If you call the method yourself without awaiting it, add a.catch()so a failed receipt does not surface as an unhandled rejection.
4.37.0
7 Aug 20262a2b2c5: Add a native Instagram Direct Messages adapter with signed webhooks, media, quick replies, story context, reactions, and typed Meta API errors.
4ac0455: Add message update and delete lifecycle callbacks, with Slack message_changed and message_deleted dispatch support.
0ec6a73: Add
@chat-adapter/notionfor Notion page and block comment discussions: webhook HMAC verification, Post+Edit streaming, conversation history,message.subjectpage metadata, plain-text@userName/@botUserIdmention detection, and File Uploads (up to 3 native attachments). Registers the adapter in thechat/adapterscatalog andcreate-chat-sdkCLI scaffold, and adds Notion emoji platform support.
Minor Changes
2a2b2c5: Add a native Instagram Direct Messages adapter with signed webhooks, media, quick replies, story context, reactions, and typed Meta API errors.
4ac0455: Add message update and delete lifecycle callbacks, with Slack message_changed and message_deleted dispatch support.
0ec6a73: Add
@chat-adapter/notionfor Notion page and block comment discussions: webhook HMAC verification, Post+Edit streaming, conversation history,message.subjectpage metadata, plain-text@userName/@botUserIdmention detection, and File Uploads (up to 3 native attachments). Registers the adapter in thechat/adapterscatalog andcreate-chat-sdkCLI scaffold, and adds Notion emoji platform support.85e3d22: Close residual gaps in agent read-tool scoping.
createChatTools's read guard now wraps modal, assistant-thread, assistant-context, app-home, app-context, and member-joined dispatch so tools built in those handlers inherit the active conversation, and it logs a warning (instead of failing open silently) when a read runs with no resolvable scope. Scoping stays channel-level by default, so a thread scope still permits sibling threads in its channel. Pass the newstrictScope: trueto confine a thread scope to that thread alone, rejecting both sibling threads and the parent channel, which matters on platforms where a channel is the widest read available (a GitHub channel is an entire repo).Note that reads inside those newly wrapped handlers were previously unscoped. An agent built in an
onModalSubmit,onAppHomeOpened, oronMemberJoinedChannelhandler that reads another channel will now be rejected. Pass an explicitscope, orscope: falsefor intentionally workspace-wide reads.
4.36.0
1 Aug 2026c5d86b1: confine built-in agent read tools to the conversation being handled, with an optional scope override
0153a39: Add
DateInputandNumberInputmodal children. The Slack adapter renders them as adatepickerand anumber_input, the Teams adapter asInput.DateandInput.Number, and both submitted values arrive inevent.valuesas strings.Teams submit values that arrive as JSON numbers are now stringified into
event.valuesinstead of being dropped. This fixesInput.Number, but applies to any numeric value a Teams dialog submits — a key that was previously absent fromevent.valueswill now be present as a string.257a32d: Route Teams personal and group conversations using their explicit conversation type so group chats use buffered fallback even when their IDs resemble direct messages.
Minor Changes
c5d86b1: confine built-in agent read tools to the conversation being handled, with an optional scope override
0153a39: Add
DateInputandNumberInputmodal children. The Slack adapter renders them as adatepickerand anumber_input, the Teams adapter asInput.DateandInput.Number, and both submitted values arrive inevent.valuesas strings.Teams submit values that arrive as JSON numbers are now stringified into
event.valuesinstead of being dropped. This fixesInput.Number, but applies to any numeric value a Teams dialog submits — a key that was previously absent fromevent.valueswill now be present as a string.
Patch Changes
257a32d: Route Teams personal and group conversations using their explicit conversation type so group chats use buffered fallback even when their IDs resemble direct messages.
b547f45: Stop treating email addresses as bot mentions. A message containing
jane@acme.comno longer triggers a bot namedacme, because the@indetectMentionmust not follow a word character. Real mentions are unaffected, including at the start of a message, after punctuation, and suffixed names such as GitHub'smybot[bot].caa6325: Add XChat support to
@chat-adapter/x, shipped from the new@chat-adapter/x/chatsubpath so it sits alongside the existing X adapter. The XChat crypto stack (@xdevplatform/chat-xdk,@xdevplatform/xdk,juicebox-sdk) is an optional peer dependency, so existing@chat-adapter/xusers are unaffected. All cryptography is handled inside the adapter via@xdevplatform/chat-xdk(wasm) and all REST goes through the typed@xdevplatform/xdkclient. Only a bot token and a Juicebox PIN are required: the bot's identity (user id and @handle) is resolved fromGET /2/users/meat startup.Encrypted send/receive in DMs and groups (webhook push + polling), signature verification on by default; undecryptable or unverified events are dropped
Webhook POSTs must carry a valid
x-twitter-webhooks-signature, which X sends on every delivery. SetconsumerSecret(orX_CONSUMER_SECRET) to receive webhooks, ordisableWebhookVerificationwhen an upstream layer already verifies them. Polling deployments are unaffectedMention detection from structured mention entities, swipe-replies to the bot, and a plain-text
@handlefallback; group replies sent as quoted repliesopenDM(userId)starts (or reuses) an encrypted 1:1, running a full key exchange when needed so the bot can message firstMedia both ways: inbound attachments with lazy download+decrypt, outbound encrypted uploads
Edit and delete of the bot's own messages; the first edit of a fresh message is age-gated by
editSafetyDelayMs(default 5000ms) so receiving clients have stored the originalReactions in and out, read receipts (
sendReadReceipts, default on), typing keep-alive, configurable group welcome messageCards degrade to text with tappable URL/mention entities plus a URL preview attachment
Requests carry a
chat-sdk-xchat/<version>User-Agent product token so Chat SDK traffic is identifiable in X API request logs (a User-Agent set viaapiHeaderstakes precedence)Registered in the
chat/adapterscatalog and thecreate-chat-sdkCLI scaffold, with a new optionalimportPathcatalog field for adapters that ship on a subpath
4.35.0
24 Jul 20264cb7e5d: Add a
chat/workflowsubpath withrequestApproval(): durable human-in-the-loop approvals built on Workflow SDK. It posts an approval card with Approve/Deny buttons, suspends the workflow until a user decides (or an optional timeout elapses), validates approvers, finalizes the card with the outcome, and returns{ approved, timedOut, user }. Also exports thebuildApprovalCardandbuildResolvedCardbuilders. Requires the new optionalworkflowpeer dependency.46681f5: Expose Microsoft Graph email addresses on normalized incoming Teams message authors. Resolved user profiles are cached in the state adapter (1 hour, failed lookups 5 minutes) so the lookup doesn't add a Graph call per message.
80def3a: Add optional
isSystemfield to the normalized messageAuthortype to distinguish platform-generated messages from humans and bots. The Slack adapter now setsisSystem: truefor messages authored by Slack's reservedUSLACKuser (e.g. "@user archived the channel" notifications in DMs), so consumers no longer need to hard-code Slack-specific user IDs.
Minor Changes
4cb7e5d: Add a
chat/workflowsubpath withrequestApproval(): durable human-in-the-loop approvals built on Workflow SDK. It posts an approval card with Approve/Deny buttons, suspends the workflow until a user decides (or an optional timeout elapses), validates approvers, finalizes the card with the outcome, and returns{ approved, timedOut, user }. Also exports thebuildApprovalCardandbuildResolvedCardbuilders. Requires the new optionalworkflowpeer dependency.46681f5: Expose Microsoft Graph email addresses on normalized incoming Teams message authors. Resolved user profiles are cached in the state adapter (1 hour, failed lookups 5 minutes) so the lookup doesn't add a Graph call per message.
Patch Changes
80def3a: Add optional
isSystemfield to the normalized messageAuthortype to distinguish platform-generated messages from humans and bots. The Slack adapter now setsisSystem: truefor messages authored by Slack's reservedUSLACKuser (e.g. "@user archived the channel" notifications in DMs), so consumers no longer need to hard-code Slack-specific user IDs.93a58af: Show explicitly configured progress as a native Teams DM status while preserving native streaming.
25f3099:
toAiMessagesno longer drops messages that have no text. A message with an empty text body is now kept when it has links or attachments the converter can include: images and text files (text/*, JSON, XML, YAML, etc.) with a workingfetchData(). Messages whose only attachments are unsupported (video, audio, other file types, or attachments withoutfetchData()) are still skipped, andonUnsupportedAttachmentnow fires for video/audio attachments on these previously filtered messages.Note: multipart
contentno longer always starts with a text part. When a kept message had no text, itscontentarray contains only attachment parts.
4.34.0
13 Jul 2026Reading the note…
4.33.0
7 Jul 2026Reading the note…
4.32.0
1 Jul 2026Reading the note…
4.31.0
16 Jun 2026Reading the note…
4.30.0
2 Jun 2026Reading the note…
4.29.0
18 May 2026Reading the note…
4.28.1
8 May 2026Reading the note…
4.27.0
30 Apr 2026Reading the note…
4.26.0
14 Apr 2026Reading the note…
4.25.0
11 Apr 2026Reading the note…
4.24.0
7 Apr 2026Reading the note…
4.23.0
26 Mar 2026Reading the note…
4.22.0
24 Mar 2026Reading the note…
4.21.0
23 Mar 2026Reading the note…
4.20.2
16 Mar 2026Reading the note…
4.20.1
12 Mar 2026Reading the note…
4.20.0
11 Mar 2026Reading the note…
4.19.0
10 Mar 2026Reading the note…
4.18.0
7 Mar 2026Reading the note…
4.17.0
6 Mar 2026Reading the note…
4.16.1
4 Mar 2026Reading the note…
4.16.0
4 Mar 2026Reading the note…
4.15.0
26 Feb 2026Reading the note…
4.14.0
24 Feb 2026Reading the note…
4.13.4
24 Feb 2026Reading the note…
4.13.3
23 Feb 2026Reading the note…
4.13.2
23 Feb 2026Reading the note…
4.13.1
20 Feb 2026Reading the note…
4.13.0
20 Feb 2026Reading the note…
4.12.0
18 Feb 2026Reading the note…
4.11.0
16 Feb 2026Reading the note…
4.10.1
15 Feb 2026Reading the note…
4.10.0
15 Feb 2026Reading the note…
4.9.1
12 Feb 2026Reading the note…
4.9.0
10 Feb 2026Reading the note…
4.8.0
6 Feb 2026Reading the note…
4.7.2
6 Feb 2026Reading the note…
4.7.1
24 Jan 2026Reading the note…
4.7.0
23 Jan 2026Reading the note…